1 /*************************************************************************
2  *  TinyFugue - programmable mud client
3  *  Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2002, 2003, 2004, 2005, 2006-2007 Ken Keys
4  *
5  *  TinyFugue (aka "tf") is protected under the terms of the GNU
6  *  General Public License.  See the file "COPYING" for details.
7  ************************************************************************/
8 
9 /***************************************************************
10  * Fugue socket handling
11  *
12  * Written by Ken Keys
13  * Reception and transmission through sockets is handled here.
14  * This module also contains the main loop.
15  * Multiple sockets handled here.
16  * Autologin handled here.
17  ***************************************************************/
18 
19 #include "tfconfig.h"
20 #include <sys/types.h>
21 #if HAVE_SYS_SELECT_H
22 # include <sys/select.h>
23 #endif
24 /* #include <sys/time.h> */
25 #include <fcntl.h>
26 #include <sys/file.h>	/* for FNONBLOCK on SVR4, hpux, ... */
27 #include <sys/socket.h>
28 #include <signal.h>	/* for killing resolver child process */
29 
30 #if WIDECHAR
31 #include <unicode/ucnv.h>
32 #include <unicode/ustring.h>
33 #endif
34 
35 #if HAVE_SSL
36 # include <openssl/ssl.h>
37 # include <openssl/err.h>
38 # include <openssl/x509v3.h>
39     SSL_CTX *ssl_ctx;
40 #endif
41 
42 #define RECEIVELIMIT ((32 * 1024) -1)
43 
44 #ifdef NETINET_IN_H
45 # include NETINET_IN_H
46 #else
47 /* Last resort - we'll assume the "normal" stuff. */
48 struct in_addr {
49 	unsigned long	s_addr;
50 };
51 struct sockaddr_in {
52 	short		sin_family;
53 	unsigned short	sin_port;
54 	struct in_addr	sin_addr;
55 	char		sin_zero[8];
56 };
57 #define	htons(x)	(x)	/* assume big-endian machine */
58 #endif
59 
60 #ifdef ARPA_INET_H
61 # include ARPA_INET_H
62 #endif
63 
64 #if HAVE_MCCP
65 # include <zlib.h>
66 #endif
67 
68 #include "port.h"
69 #include "tf.h"
70 #include "util.h"
71 #include "pattern.h"
72 #include "search.h"
73 #include "tfio.h"
74 #include "tfselect.h"
75 #include "history.h"
76 #include "world.h"
77 #include "socket.h"
78 #include "output.h"
79 #include "attr.h"
80 #include "process.h"
81 #include "macro.h"
82 #include "keyboard.h"
83 #include "cmdlist.h"
84 #include "command.h"
85 #include "signals.h"
86 #include "variable.h"	/* set_var_by_*() */
87 
88 #if WIDECHAR
89 #include <wchar.h>
90 #endif
91 
92 #ifdef _POSIX_VERSION
93 # include <sys/wait.h>
94 #endif
95 
96 #if !defined(AF_INET6) || !defined(IN6_ADDR) || !HAVE_GETADDRINFO
97 # undef ENABLE_INET6
98 # define ENABLE_INET6 0
99 #endif
100 
101 #ifndef INET_ADDRSTRLEN
102 #define INET_ADDRSTRLEN 16
103 #endif
104 #ifndef INET6_ADDRSTRLEN
105 #define INET6_ADDRSTRLEN 46
106 #endif
107 
108 #ifdef PLATFORM_OS2
109 # define NONBLOCKING_GETHOST
110 #endif
111 
112 #ifdef PLATFORM_UNIX
113 # ifndef __CYGWIN32__
114 #  if HAVE_WAITPID
115 #   define NONBLOCKING_GETHOST
116 #  endif
117 # endif
118 #endif
119 
120 #ifdef NETDB_H
121 # include NETDB_H
122 #endif
123 
124 extern struct World   *world_decl;     /* declares struct World */
125 
126 #if !HAVE_GAI_STRERROR || !defined(AI_NUMERICHOST) || !defined(EAI_SERVICE)
127   /* System's implementation is incomplete.  Avoid it. */
128 # undef HAVE_GETADDRINFO
129 #endif
130 
131 #define TF_EAI_ADDRFAMILY  -1 /* address family for hostname not supported */
132 #define TF_EAI_AGAIN       -2 /* temporary failure in name resolution */
133 #define TF_EAI_BADFLAGS    -3 /* invalid value for ai_flags */
134 #define TF_EAI_FAIL        -4 /* non-recoverable failure in name resolution */
135 #define TF_EAI_FAMILY      -5 /* ai_family not supported */
136 #define TF_EAI_MEMORY      -6 /* memory allocation failure */
137 #define TF_EAI_NODATA      -7 /* no address associated with hostname */
138 #define TF_EAI_NONAME      -8 /* hostname nor servname provided, or not known */
139 #define TF_EAI_SERVICE     -9 /* servname not supported for ai_socktype */
140 #define TF_EAI_SOCKTYPE   -10 /* ai_socktype not supported */
141 #define TF_EAI_SYSTEM     -11 /* system error returned in errno */
142 #define TF_EAI_BADHINTS   -12
143 #define TF_EAI_PROTOCOL   -13
144 #define TF_EAI_MAX        -14
145 
146 static const char *tf_gai_errlist[] = {
147     "Error 0",
148     "address family for hostname not supported",
149     "temporary failure in name resolution",
150     "invalid value for ai_flags",
151     "non-recoverable failure in name resolution",
152     "ai_family not supported",
153     "memory allocation failure",
154     "no address associated with hostname",
155     "hostname nor servname provided, or not known",
156     "unknown service (port) name",
157     "ai_socktype not supported",
158     "system error returned in errno",
159 };
160 
161 #if HAVE_GETADDRINFO
162 /* The standard message for EAI_SERVICE is horrible.  We override it. */
163 # define gai_strerror(err) \
164     ((err) == EAI_SERVICE ? tf_gai_errlist[-TF_EAI_SERVICE] : (gai_strerror)(err))
165 
166 #else /* !HAVE_GETADDRINFO */
167 /* Partial implementation of getaddrinfo() and friends */
168 # define addrinfo tfaddrinfo
169 # define getaddrinfo tfgetaddrinfo
170 # define freeaddrinfo tffreeaddrinfo
171 
172 struct tfaddrinfo {
173     int     ai_flags;     /* AI_PASSIVE, AI_CANONNAME, AI_NUMERICHOST */
174     int     ai_family;    /* PF_xxx */
175     int     ai_socktype;  /* SOCK_xxx */
176     int     ai_protocol;  /* 0 or IPPROTO_xxx for IPv4 and IPv6 */
177     size_t  ai_addrlen;   /* length of ai_addr */
178     char   *ai_canonname; /* canonical name for nodename */
179     struct sockaddr  *ai_addr; /* binary address */
180     struct addrinfo  *ai_next; /* next structure in linked list */
181 };
182 
183 #define AI_NUMERICHOST  0x00000004 /* prevent name resolution */
184 #define AI_ADDRCONFIG   0x00000400 /* only if any address is assigned */
185 
186 # if !HAVE_HSTRERROR
187 static const char *h_errlist[] = {
188     "Error 0",
189     "Unknown host",
190     "Host name lookup failure",
191     "Unknown server error",
192     "No address associated with name"
193 };
194 #  define hstrerror(err)  ((err) <= 4 ? h_errlist[(err)] : "unknown error")
195 # endif /* !HAVE_HSTRERROR */
196 
197 #if HAVE_H_ERRNO
198   /* extern int h_errno; */ /* this could conflict */
199 #elif !defined(h_errno)
200 # define h_errno 1
201 #endif
202 
203 # define gai_strerror(err) ((err) < 0 ? tf_gai_errlist[-(err)] : hstrerror(err))
204 
205 #endif /* !HAVE_GETADDRINFO */
206 
207 #ifdef NONBLOCKING_GETHOST
208 # ifndef PLATFORM_OS2
209 #  include <sys/uio.h> /* child uses writev() */
210 # endif
211   static void waitforhostname(int fd, const char *name, const char *port);
212   static int nonblocking_gethost(const char *name, const char *port,
213       struct addrinfo **addrs, pid_t *pidp, const char **what);
214 #endif
215 
216 #ifndef INADDR_NONE
217 # define INADDR_NONE 0xffffffff     /* should be in <netinet/in.h> */
218 #endif
219 
220 
221 /* Nonblocking connect.
222  * Legend for comment columns:
223  *      W = works, N = not defined, F = defined but fails, ? = unknown
224  * Nonblocking connect will work on a system if the column contains a 'W'
225  * and there is no 'F' above it; 'N' does not matter.  The order of the
226  * tests is arranged to keep the 'F's below the 'W's.
227  *
228  *                                                        S
229  *                                                        o
230  *                                      P           L  S  l     H
231  *                                      O     S     i  u  a  I  P
232  *                                      S  B  Y  A  n  n  r  R  /
233  *                                      I  S  S  I  u  O  i  I  U
234  *                                      X  D  V  X  x  S  s  X  X
235  */
236 #ifdef FNONBLOCK                     /* N  ?  W  W  N  ?  W  W  W */
237 # define TF_NONBLOCK FNONBLOCK
238 #else
239 # ifdef O_NONBLOCK                   /* W  ?  ?  W  W  ?  W  W  ? */
240 #  define TF_NONBLOCK O_NONBLOCK
241 # else
242 #  ifdef FNDELAY                     /* ?  W  ?  F  W  ?  W  W  ? */
243 #   define TF_NONBLOCK FNDELAY
244 #  else
245 #   ifdef O_NDELAY                   /* ?  W  ?  F  W  ?  W  W  ? */
246 #    define TF_NONBLOCK O_NDELAY
247 #   else
248 #    ifdef FNBIO                     /* ?  ?  W  N  N  F  N  N  ? */
249 #     define TF_NONBLOCK FNBIO
250 #    else
251 #     ifdef FNONBIO                  /* ?  ?  ?  N  N  F  N  N  ? */
252 #      define TF_NONBLOCK FNONBIO
253 #     else
254 #      ifdef FNONBLK                 /* ?  ?  ?  N  N  ?  N  W  ? */
255 #       define TF_NONBLOCK FNONBLK
256 #      else
257 #       define TF_NONBLOCK 0
258 #      endif
259 #     endif
260 #    endif
261 #   endif
262 #  endif
263 # endif
264 #endif
265 
266 
267 #ifdef TF_AIX_DECLS
268 extern int connect(int, struct sockaddr *, int);
269 #endif
270 
271 #if SOCKS
272 # ifndef SOCKS_NONBLOCK
273 #  define TF_NONBLOCK 0
274 # endif
275 #endif
276 
277 /* connection states */
278 typedef enum {
279     SS_NEW,		/* brand spanking new */
280     SS_RESOLVING,	/* hostname resolution is pending */
281     SS_RESOLVED,	/* hostname resolution is complete */
282     SS_CONNECTING,	/* connection is pending */
283     SS_CONNECTED,	/* connection is established */
284     SS_OPEN,		/* open, without a connection */
285     SS_ZOMBIE,		/* connection dead, but some text may be unseen */
286     SS_DEAD		/* connection dead, and all text has been seen */
287 } constate_t;
288 
289 /* flags */
290 #define SOCKLOGIN	0x01	/* autologin requested by user */
291 #define SOCKPROMPT	0x02	/* last prompt was definitely a prompt */
292 #define SOCKPROXY	0x04	/* indirect connection through proxy server */
293 #define SOCKTELNET	0x08	/* server supports telnet protocol */
294 #define SOCKMAYTELNET	0x10	/* server might support telnet protocol */
295 #define SOCKCOMPRESS	0x20	/* server has enabled MCCP v1 or v2 */
296 #define SOCKALLOCADDRS	0x40	/* addrs allocated by tf, not getaddrinfo */
297 #define SOCKECHO	0x80	/* receive all sent text (loopback) */
298 
299 VEC_TYPEDEF(telnet_opts, 256);
300 
301 typedef struct Sock {		/* an open connection to a server */
302     int fd;			/* socket to server, or pipe to name resolver */
303     const char *host, *port;	/* server address, human readable */
304     struct addrinfo *addrs;	/* possible server addresses */
305     struct addrinfo *addr;	/* actual server address */
306     const char *myhost;		/* explicit client address, human readable */
307     struct addrinfo *myaddr;	/* explicit client address */
308     telnet_opts tn_us;		/* our telnet options */
309     telnet_opts tn_us_tog;	/* our telnet options we want changed */
310     telnet_opts tn_them;	/* server's telnet options */
311     telnet_opts tn_them_tog;	/* server's telnet options we want changed */
312     constate_t constate;	/* connection state */
313     unsigned char flags;	/* SOCK* flags */
314     short numquiet;		/* # of lines to gag after connecting */
315     struct World *world;	/* world to which socket is connected */
316     struct Sock *next, *prev;	/* next/prev sockets in linked list */
317 #if WIDECHAR
318     Stringp incomingposttelnet;	/* incoming text stripped of telnet commands */
319     UConverter *incomingfsm;	/* converter for incomingposttelnet to buffer */
320 #endif
321     Stringp buffer;		/* above buffer processed into UTF-8 */
322     Stringp subbuffer;		/* buffer for processing telnet commands */
323     Queue queue;		/* queue of incoming lines */
324     conString *prompt;		/* prompt from server */
325     struct timeval prompt_timeout; /* when does unterm'd line become a prompt */
326     int ttype;			/* index into enum_ttype[] */
327     attr_t attrs;		/* current text attributes */
328     attr_t prepromptattrs;	/* text attributes before implicit prompt */
329     unsigned long alert_id;	/* id of last alert on this socket */
330     struct timeval time[2];	/* time of last receive/send */
331     char fsastate;		/* parser finite state automaton state */
332     char substate;		/* parser fsa state for telnet subnegotiation */
333     pid_t pid;			/* OS pid of name resolution process */
334 #if HAVE_MCCP
335     z_stream *zstream;		/* state of compressed stream */
336 #endif
337 #if HAVE_SSL
338     SSL *ssl;			/* SSL state */
339 #endif
340 } Sock;
341 
342 typedef struct {
343     int err;
344     size_t size;
345 } nbgai_hdr_t;
346 
347 static Sock *find_sock(const char *name);
348 static void  wload(World *w);
349 static int   fg_sock(Sock *sock, int quiet);
350 static int   get_host_address(Sock *sock, const char **what, int *errp);
351 #if !HAVE_GETADDRINFO
352 static int   tfgetaddrinfo(const char *nodename, const char *port,
353 	     const struct addrinfo *hints, struct addrinfo **res);
354 #endif
355 static int   opensock(World *world, int flags);
356 static int   openconn(Sock *new);
357 static int   establish(Sock *new);
358 #if 0
359 static void  fg_live_sock(void);
360 #endif
361 static void  nuke_dead_socks(void);
362 static void  nukesock(Sock *sock);
363 static void  handle_prompt(String *str, int offset, int confirmed);
364 static void  handle_implicit_prompt(void);
365 static void  unprompt(Sock *sock, int update);
366 static void  test_prompt(void);
367 static void  schedule_prompt(Sock *sock);
368 static void  handle_socket_lines(void);
369 #if WIDECHAR
370 static int   inbound_decode_str(String *outut, String *input, UConverter *conv, const char cflush);
371 static int   inbound_decode(String *output, const char *input, const char *iendptr, UConverter *conv, const char cflush);
372 #endif
373 static int   handle_socket_input(const char *simbuffer, int simlen, const char* encoding);
374 static void  handle_socket_input_queue_lines(Sock *sock);
375 static int   transmit(const char *s, unsigned int len);
376 static void  telnet_send(String *cmd);
377 static void  telnet_subnegotiation(void);
378 static void  f_telnet_recv(int cmd, int opt);
379 static int   is_quiet(const char *str);
380 static int   is_bamf(const char *str);
381 static void  do_naws(Sock *sock);
382 static void  telnet_debug(const char *dir, const char *str, int len);
383 static void  preferred_telnet_options(void);
384 static void  killsock(Sock *sock);
385 #if HAVE_SSL
386 static int   ssl_check_cert_verify(Sock *sock);
387 static int   ssl_verify_callback(int preverify_ok, X509_STORE_CTX *ctx);
388 #endif
389 
390 #define zombiesock(sock)	killsock(sock)
391 #define flushxsock() \
392     do { if (xsock->queue.list.head) handle_socket_lines(); } while (0)
393 
394 #define telnet_recv(cmd, opt)	f_telnet_recv((UCHAR)cmd, (UCHAR)opt);
395 #define no_reply(str) telnet_debug("sent", "[no reply (" str ")", 0)
396 
397 #ifndef CONN_WAIT
398 #define CONN_WAIT 400000
399 #endif
400 
401 #ifndef PROC_WAIT
402 #define PROC_WAIT 100000
403 #endif
404 
405 #define BUFFSIZE (4*1024)       /* how big are our byte-buffers? */
406 #define SPAM (4*1024)		/* break loop if this many chars are received */
407 
408 static fd_set readers;		/* input file descriptors */
409 static fd_set active;		/* active file descriptors */
410 static fd_set writers;		/* pending connections */
411 static fd_set connected;	/* completed connections */
412 static unsigned int nfds;	/* max # of readers/writers */
413 static Sock *hsock = NULL;	/* head of socket list */
414 static Sock *tsock = NULL;	/* tail of socket list */
415 static Sock *fsock = NULL;	/* foreground socket */
416 static int dead_socks = 0;	/* Number of unnuked dead sockets */
417 static int socks_with_lines = 0;/* Number of socks with queued received lines */
418 static struct timeval prompt_timeout = {0,0};
419 static const char *telnet_label[0x100];
420 STATIC_BUFFER(telbuf);
421 
422 #define MAXQUIET        25	/* max # of lines to suppress during login */
423 
424 static const char *enum_charset[] = {
425     "UTF-8",
426     "ISO-8859-1", /* No real support; code passes all chars */
427     "US-ASCII",
428     "" /* Null-terminated list, so we can loop */
429 };
430 
431 /* Note: many telnet servers send DO ECHO and DO SGA together to mean
432  * character-at-a-time mode.
433  */
434 
435 /* TELNET special characters (RFC 854) */
436 #define TN_EOR		((char)239)	/* end of record (RFC 885) */
437 #define TN_SE		((char)240)	/* subnegotiation end */
438 #define TN_NOP		((char)241)	/* no operation */
439 #define TN_DATA_MARK	((char)242)	/* (not used) */
440 #define TN_BRK		((char)243)	/* break (not used) */
441 #define TN_IP		((char)244)	/* interrupt process (not used) */
442 #define TN_AO		((char)245)	/* abort output (not used) */
443 #define TN_AYT		((char)246)	/* are you there? (not used) */
444 #define TN_EC		((char)247)	/* erase character (not used) */
445 #define TN_EL		((char)248)	/* erase line (not used) */
446 #define TN_GA		((char)249)	/* go ahead */
447 #define TN_SB		((char)250)	/* subnegotiation begin */
448 #define TN_WILL		((char)251)	/* I offer to ~, or ack for DO */
449 #define TN_WONT		((char)252)	/* I will stop ~ing, or nack for DO */
450 #define TN_DO		((char)253)	/* Please do ~?, or ack for WILL */
451 #define TN_DONT		((char)254)	/* Stop ~ing!, or nack for WILL */
452 #define TN_IAC		((char)255)	/* telnet Is A Command character */
453 
454 /* TELNET options (RFC 855) */		/* RFC# - description */
455 #define TN_BINARY	((char)0)	/*  856 - transmit binary */
456 #define TN_ECHO		((char)1)	/*  857 - echo */
457 #define TN_SGA		((char)3)	/*  858 - suppress GA (not used) */
458 #define TN_STATUS	((char)5)	/*  859 - (not used) */
459 #define TN_TIMING_MARK	((char)6)	/*  860 - (not used) */
460 #define TN_TTYPE	((char)24)	/* 1091 - terminal type */
461 #define TN_SEND_EOR	((char)25)	/*  885 - transmit EOR */
462 #define TN_NAWS		((char)31)	/* 1073 - negotiate about window size */
463 #define TN_TSPEED	((char)32)	/* 1079 - terminal speed (not used) */
464 #define TN_FLOWCTRL	((char)33)	/* 1372 - (not used) */
465 #define TN_LINEMODE	((char)34)	/* 1184 - (not used) */
466 #define TN_XDISPLOC	((char)35)	/* 1096 - (not used) */
467 #define TN_ENVIRON	((char)36)	/* 1408 - (not used) */
468 #define TN_AUTH		((char)37)	/* 1416 - (not used) */
469 #define TN_NEW_ENVIRON	((char)39)	/* 1572 - (not used) */
470 #define TN_CHARSET	((char)42)	/* 2066 - Charset negotiation */
471 /* 85 & 86 are not standard.  See http://www.randomly.org/projects/MCCP/ */
472 #define TN_COMPRESS	((char)85)	/* MCCP v1 */
473 #define TN_COMPRESS2	((char)86)	/* MCCP v2 */
474 /* 200 is not standard. See http://www.ironrealms.com/rapture/manual/files/FeatATCP-txt.html */
475 #define TN_ATCP		((char)200)	/* ATCP */
476 /* 201 is not standard. See http://www.aardwolf.com/wiki/index.php/Clients/GMCP */
477 #define TN_GMCP		((char)201)	/* GMCP */
478 /* 102 is not standard. See http://www.aardwolf.com/blog/category/technical */
479 #define TN_102	((char)102)	/* Option 102 */
480 
481 #define UCHAR		unsigned char
482 
483 #define tn_send_opt(cmd, opt) \
484     ( Sprintf(telbuf, "%c%c%c", TN_IAC, (cmd), (opt)), telnet_send(telbuf) )
485 
486 #define TELOPT(sock, field, opt) \
487 	VEC_ISSET((UCHAR)(opt), &(sock)->tn_ ## field)
488 #define SET_TELOPT(sock, field, opt) \
489 	VEC_SET((UCHAR)(opt), &(sock)->tn_ ## field)
490 #define CLR_TELOPT(sock, field, opt) \
491 	VEC_CLR((UCHAR)(opt), &(sock)->tn_ ## field)
492 
493 #define DO(opt)		( tn_send_opt(TN_DO,   (opt)) )
494 #define DONT(opt)	( tn_send_opt(TN_DONT, (opt)) )
495 #define WILL(opt)	( tn_send_opt(TN_WILL, (opt)) )
496 #define WONT(opt)	( tn_send_opt(TN_WONT, (opt)) )
497 
498 #define ANSI_CSI	'\233'	/* ANSI terminal Command Sequence Intro */
499 
500 #if HAVE_MCCP /* hack for broken MCCPv1 subnegotiation */
501 char mccp1_subneg[] = { TN_IAC, TN_SB, TN_COMPRESS, TN_WILL, TN_SE };
502 #endif
503 
504 Sock *xsock = NULL;		/* current (transmission) socket */
505 int quit_flag = FALSE;		/* Are we all done? */
506 int active_count = 0;		/* # of (non-current) active sockets */
507 String *incoming_text = NULL;
508 const int feature_IPv6 = ENABLE_INET6 - 0;
509 const int feature_MCCPv1 = HAVE_MCCP - 0;
510 const int feature_MCCPv2 = HAVE_MCCP - 0;
511 const int feature_ssl = HAVE_SSL - 0;
512 const int feature_SOCKS = SOCKS - 0;
513 
514 static const char *CONFAIL_fmt = "%% Connection to %s failed: %s: %s";
515 static const char *ICONFAIL_fmt = "%% Intermediate connection to %s failed: %s: %s";
516 
517 #define ICONFAIL_AI(sock, why) \
518     ICONFAIL((sock), printai((sock)->addr, NULL), (why))
519 
520 #define CONFAILHP(sock, why) \
521 do { \
522     do_hook(H_CONFAIL, "%% Unable to connect to %s: %s %s: %s", "%s %s %s: %s", \
523         (sock)->world->name, (sock)->world->host, (sock)->world->port, (why)); \
524     oflush(); \
525 } while (0)
526 
527 #define CONFAIL(sock, what, why) \
528 do { \
529     do_hook(H_CONFAIL, CONFAIL_fmt, "%s %s %s", \
530 	(sock)->world->name, (what), (why)); \
531     oflush(); \
532 } while (0)
533 
534 #define DISCON(where, what, why) \
535     do_hook(H_DISCONNECT, "%% Connection to %s closed: %s: %s", "%s %s: %s", \
536 	where, what, why)
537 
538 #define ROUND_UP_LENGTH(len)	((len + 7) & -8)
539 
540 #if HAVE_SSL
ssl_err(const char * str)541 static void ssl_err(const char *str)
542 {
543     unsigned long e;
544     while ((e = ERR_get_error()))
545 	eprintf("%s: %s", str, ERR_error_string(e, NULL));
546 }
547 
ssl_io_err(Sock * sock,int ret,int hook)548 static void ssl_io_err(Sock *sock, int ret, int hook)
549 {
550     /* NB: sock->addr may have already been changed by setupnextconn() */
551     int err;
552     const char *fmt;
553 
554     flushxsock();
555 
556     switch (hook) {
557     case H_CONFAIL: fmt = CONFAIL_fmt; break;
558     case H_ICONFAIL: fmt = ICONFAIL_fmt; break;
559     case H_DISCONNECT: fmt = "%% Connection to %s closed: %s: %s"; break;
560     }
561 
562 #define ssl_io_err_hook(what, why) \
563     do_hook(hook, fmt, "%s %s %s", xsock->world->name, what, why);
564 
565     err = SSL_get_error(sock->ssl, ret);
566     switch (err) {
567     case SSL_ERROR_NONE:
568 	break;
569     case SSL_ERROR_ZERO_RETURN:
570 	ssl_io_err_hook("SSL", "SSL_ERROR_ZERO_RETURN");
571 	break;
572     case SSL_ERROR_WANT_READ:
573 	ssl_io_err_hook("SSL", "SSL_ERROR_WANT_READ");
574 	break;
575     case SSL_ERROR_WANT_WRITE:
576 	ssl_io_err_hook("SSL", "SSL_ERROR_WANT_WRITE");
577 	break;
578     case SSL_ERROR_WANT_CONNECT:
579 	ssl_io_err_hook("SSL", "SSL_ERROR_WANT_CONNECT");
580 	break;
581     case SSL_ERROR_SYSCALL:
582 	if (ret == 0) {
583 	    ssl_io_err_hook("SSL/system", "invalid EOF");
584 	} else if (ret == -1) {
585 	    ssl_io_err_hook("SSL/system", strerror(errno));
586 	} else {
587 	    while ((err = ERR_get_error())) {
588 		ssl_io_err_hook("SSL/system", ERR_error_string(err, NULL));
589 	    }
590 	}
591 	break;
592     case SSL_ERROR_SSL:
593 	while ((err = ERR_get_error())) {
594 	    ssl_io_err_hook("SSL/lib", ERR_error_string(err, NULL));
595 	}
596 	break;
597     }
598 }
599 
600 /*
601  * cert verify, from openssl example eg:
602  *    https://www.openssl.org/docs/man1.1.0/ssl/SSL_CTX_set_verify.html
603  */
604 typedef struct {
605     int verbose_mode;
606     int verify_depth;
607     int always_continue;
608 } ssl_options_t;
609 static ssl_options_t ssl_options;
610 static int ssl_mydata_index;
611 
ssl_verify_callback(int preverify_ok,X509_STORE_CTX * ctx)612 static int ssl_verify_callback(int preverify_ok, X509_STORE_CTX *ctx)
613 {
614     char    buf[256];
615     X509   *err_cert;
616     int     err, depth;
617     SSL    *ssl;
618     ssl_options_t *ssl_options;
619 
620     err_cert = X509_STORE_CTX_get_current_cert(ctx);
621     err = X509_STORE_CTX_get_error(ctx);
622     depth = X509_STORE_CTX_get_error_depth(ctx);
623 
624     /*
625      * Retrieve the pointer to the SSL of the connection currently treated
626      * and the application specific data stored into the SSL object.
627      */
628     ssl = X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx());
629     ssl_options = SSL_get_ex_data(ssl, ssl_mydata_index);
630     if (ssl_options == NULL) {
631 	eprintf("ssl: ssl_options null");
632     }
633 
634     X509_NAME_oneline(X509_get_subject_name(err_cert), buf, 256);
635 
636     /*
637      * Catch a too long certificate chain. The depth limit set using
638      * SSL_CTX_set_verify_depth() is by purpose set to "limit+1" so
639      * that whenever the "depth>verify_depth" condition is met, we
640      * have violated the limit and want to log this error condition.
641      * We must do it here, because the CHAIN_TOO_LONG error would not
642      * be found explicitly; only errors introduced by cutting off the
643      * additional certificates would be logged.
644      */
645 
646     if (depth > ssl_options->verify_depth) {
647 	do_hook(H_PENDING, "%% SSL: cert verify depth exceeded: allowed=%d actual=%d", "%d %d", ssl_options->verify_depth, depth);
648 	preverify_ok = 0;
649 	err = X509_V_ERR_CERT_CHAIN_TOO_LONG;
650 	X509_STORE_CTX_set_error(ctx, err);
651     }
652     if (!preverify_ok) {
653 	do_hook(H_PENDING, "%% SSL: cert verify error: err=%d '%s' depth:%d cn:%s", "%d %s %d %s", err, X509_verify_cert_error_string(err), depth, buf);
654     }
655     else if (ssl_options->verbose_mode) {
656 	// eprintf("depth=%d:%s", depth, buf);
657 	do_hook(H_PENDING, "%% SSL: chain: depth:%d cn:%s", "%d %s", depth, buf);
658     }
659 
660     /*
661      * At this point, err contains the last verification error. We can use
662      * it for something special
663      */
664     if (!preverify_ok && (err == X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT)) {
665 	X509_NAME_oneline(X509_get_issuer_name(err_cert), buf, 256);
666 	eprintf("issuer= %s", buf);
667     }
668 
669     if (ssl_options->always_continue)
670 	return 1;
671     else
672 	return preverify_ok;
673 }
674 
init_ssl(void)675 static void init_ssl(void)
676 {
677     SSL_load_error_strings();
678     SSL_library_init();
679     /* XXX seed PRNG */
680     ssl_ctx = SSL_CTX_new(SSLv23_client_method());
681     if (!ssl_ctx) {
682 	ssl_err("SSL_CTX_new");
683 	return;
684     }
685     if (!SSL_CTX_set_cipher_list(ssl_ctx, "ALL")) {
686 	ssl_err("SSL_CTX_set_cipher_list");
687 	return;
688     }
689     SSL_CTX_set_default_verify_paths(ssl_ctx);
690     if (ssl_ca_file || ssl_ca_dir) {
691 	if (SSL_CTX_load_verify_locations(ssl_ctx, ssl_ca_file, ssl_ca_dir) < 1) {
692 	    eprintf("ssl: SSL_CTX_load_verify_locations: nothing loaded");
693 	    ssl_err("SSL_CTX_load_verify_locations");
694 	    eprintf("ssl: SSL_CTX_load_verify_locations: ssl_ca_file=%s", ssl_ca_file);
695 	    eprintf("ssl: SSL_CTX_load_verify_locations: ssl_ca_dir=%s", ssl_ca_dir);
696 	}
697     }
698 }
699 #endif
700 
701 /* initialize socket.c data */
init_sock(void)702 void init_sock(void)
703 {
704     int i;
705 
706     FD_ZERO(&readers);
707     FD_ZERO(&active);
708     FD_ZERO(&writers);
709     FD_ZERO(&connected);
710     FD_SET(STDIN_FILENO, &readers);
711     nfds = 1;
712 
713     set_var_by_id(VAR_async_conn, !!TF_NONBLOCK);
714 #ifdef NONBLOCKING_GETHOST
715     set_var_by_id(VAR_async_name, 1);
716 #endif
717 
718     for (i = 0; i < 0x100; i++) telnet_label[i] = NULL;
719 
720     telnet_label[(UCHAR)TN_BINARY]	= "BINARY";
721     telnet_label[(UCHAR)TN_ECHO]	= "ECHO";
722     telnet_label[(UCHAR)TN_SGA]		= "SUPPRESS-GO-AHEAD";
723     telnet_label[(UCHAR)TN_STATUS]	= "STATUS";
724     telnet_label[(UCHAR)TN_TIMING_MARK]	= "TIMING-MARK";
725     telnet_label[(UCHAR)TN_TTYPE]	= "TERMINAL-TYPE";
726     telnet_label[(UCHAR)TN_SEND_EOR]	= "SEND-EOR";
727     telnet_label[(UCHAR)TN_NAWS]	= "NAWS";
728     telnet_label[(UCHAR)TN_TSPEED]	= "TSPEED";
729     telnet_label[(UCHAR)TN_FLOWCTRL]	= "TOGGLE-FLOW-CONTROL";
730     telnet_label[(UCHAR)TN_LINEMODE]	= "LINEMODE";
731     telnet_label[(UCHAR)TN_XDISPLOC]	= "XDISPLOC";
732     telnet_label[(UCHAR)TN_ENVIRON]	= "ENVIRON";
733     telnet_label[(UCHAR)TN_AUTH]	= "AUTHENTICATION";
734     telnet_label[(UCHAR)TN_NEW_ENVIRON]	= "NEW-ENVIRON";
735     telnet_label[(UCHAR)TN_CHARSET]	= "CHARSET";
736     telnet_label[(UCHAR)TN_COMPRESS]	= "COMPRESS";
737     telnet_label[(UCHAR)TN_COMPRESS2]	= "COMPRESS2";
738     telnet_label[(UCHAR)TN_ATCP]	= "ATCP";
739     telnet_label[(UCHAR)TN_GMCP]	= "GMCP";
740     telnet_label[(UCHAR)TN_102]		= "102";
741     telnet_label[(UCHAR)TN_EOR]		= "EOR";
742     telnet_label[(UCHAR)TN_SE]		= "SE";
743     telnet_label[(UCHAR)TN_NOP]		= "NOP";
744     telnet_label[(UCHAR)TN_DATA_MARK]	= "DATA-MARK";
745     telnet_label[(UCHAR)TN_BRK]		= "BRK";
746     telnet_label[(UCHAR)TN_IP]		= "IP";
747     telnet_label[(UCHAR)TN_AO]		= "AO";
748     telnet_label[(UCHAR)TN_AYT]		= "AYT";
749     telnet_label[(UCHAR)TN_EC]		= "EC";
750     telnet_label[(UCHAR)TN_EL]		= "EL";
751     telnet_label[(UCHAR)TN_GA]		= "GA";
752     telnet_label[(UCHAR)TN_SB]		= "SB";
753     telnet_label[(UCHAR)TN_WILL]	= "WILL";
754     telnet_label[(UCHAR)TN_WONT]	= "WONT";
755     telnet_label[(UCHAR)TN_DO]		= "DO";
756     telnet_label[(UCHAR)TN_DONT]	= "DONT";
757     telnet_label[(UCHAR)TN_IAC]		= "IAC";
758 
759 }
760 
761 #define set_min_earliest(tv) \
762     do { \
763 	if (earliest.tv_sec == 0 || (tvcmp(&tv, &earliest) < 0)) { \
764 	    earliest = tv; \
765 	} \
766     } while (0)
767 
768 /* main_loop
769  * Here we mostly sit in select(), waiting for something to happen.
770  * The select timeout is set for the earliest process, mail check,
771  * or refresh event.  Signal processing and garbage collection is
772  * done at the beginning of each loop, where we're in a "clean" state.
773  */
main_loop(void)774 void main_loop(void)
775 {
776     static struct timeval now, earliest;    /* static, for recursion */
777     Sock *sock = NULL;		/* loop index */
778     static int count;		/* select count; remembered across recursion */
779     int received;
780     Sock *stopsock;
781     static int depth = 0;
782     struct timeval tv, *tvp;
783     struct timeval refresh_tv;
784     STATIC_STRING(low_memory_msg,
785 	"% WARNING: memory is low.  Try reducing history sizes.", 0);
786 
787     depth++;
788     while (!quit_flag) {
789         if (depth > 1 && interrupted()) break;
790 
791         /* deal with pending signals */
792         /* at loop beginning in case of signals before main_loop() */
793         process_signals();
794 
795         /* run processes */
796         /* at loop beginning in case of processes before main_loop() */
797         gettime(&now);
798         if (proctime.tv_sec && tvcmp(&proctime, &now) <= 0)
799 	    runall(0, NULL); /* run timed processes */
800 
801         if (low_memory_warning) {
802             low_memory_warning = 0;
803 	    tfputline(low_memory_msg, tferr);
804         }
805 
806         if (quit_flag) break;
807 
808         /* figure out when next event is so select() can timeout then */
809         gettime(&now);
810         earliest = proctime;
811 #if 1 /* XXX debugging */
812 	{
813 	    Sock *s;
814 	    int n = 0;
815 	    for (s = hsock; s; s = s->next)
816 		if (s->queue.list.head) n++;
817 	    if (n != socks_with_lines) {
818 		internal_error(__FILE__, __LINE__,
819 		    "socks_with_lines (%d) is not correct (%d)!",
820 		    socks_with_lines, n);
821 		socks_with_lines = n;
822 	    }
823 	}
824 #endif
825 	if (socks_with_lines)
826 	    earliest = now;
827         if (maillist && tvcmp(&maildelay, &tvzero) > 0) {
828             if (tvcmp(&now, &mail_update) >= 0) {
829                 check_mail();
830                 tvadd(&mail_update, &now, &maildelay);
831             }
832 	    set_min_earliest(mail_update);
833         }
834         if (visual && alert_timeout.tv_sec > 0) {
835             if (tvcmp(&alert_timeout, &now) < 0) {
836 		clear_alert();
837 	    } else {
838 		set_min_earliest(alert_timeout);
839             }
840 	}
841         if (visual && clock_update.tv_sec > 0) {
842             if (now.tv_sec >= clock_update.tv_sec)
843                 update_status_field(NULL, STAT_CLOCK);
844 	    set_min_earliest(clock_update);
845         }
846         if (prompt_timeout.tv_sec > 0) {
847 	    set_min_earliest(prompt_timeout);
848 	}
849 
850         /* flush pending display_screen output */
851         /* must be after all possible output and before select() */
852         oflush();
853 
854         if (pending_input || pending_line) {
855             tvp = &tv;
856             tv = tvzero;
857         } else if (earliest.tv_sec) {
858             tvp = &tv;
859             if (tvcmp(&earliest, &now) <= 0) {
860                 tv = tvzero;
861             } else {
862                 tvsub(&tv, &earliest, &now);
863 #if !HAVE_GETTIMEOFDAY
864                 /* We can't read microseconds, so we get within the right
865                  * second and then start polling. */
866                 if (proctime.tv_sec) {
867                     if ((--tv.tv_sec) == 0)
868                         tv.tv_usec = PROC_WAIT;
869                 }
870 #endif
871             }
872         } else tvp = NULL;
873 
874         if (need_refresh) {
875             if (!visual) {
876                 refresh_tv.tv_sec = refreshtime / 1000000;
877                 refresh_tv.tv_usec = refreshtime % 1000000;
878             } else {
879                 refresh_tv = tvzero;
880             }
881 
882             if (!tvp || refresh_tv.tv_sec < tvp->tv_sec ||
883                 (refresh_tv.tv_sec == tvp->tv_sec &&
884                 refresh_tv.tv_usec < tvp->tv_usec))
885             {
886                 tvp = &refresh_tv;
887             }
888         }
889 
890         if (visual && need_more_refresh) {
891             if (!tvp || 1 < tvp->tv_sec ||
892                 (1 == tvp->tv_sec && 0 < tvp->tv_usec))
893             {
894                 refresh_tv.tv_sec = 1;
895                 refresh_tv.tv_usec = 0;
896                 tvp = &refresh_tv;
897             }
898         }
899 
900         /* Wait for next event.
901          *   descriptor read:	user input, socket input, or /quote !
902          *   descriptor write:	nonblocking connect()
903          *   timeout:		time for runall() or do_refresh()
904          * Note: if the same descriptor appears in more than one fd_set, some
905          * systems count it only once, some count it once for each occurance.
906          */
907         active = readers;
908         connected = writers;
909         count = tfselect(nfds, &active, &connected, NULL, tvp);
910 
911         if (count < 0) {
912             /* select() must have exited due to error or interrupt. */
913             if (errno != EINTR) core(strerror(errno), __FILE__, __LINE__, 0);
914             /* In case we're in a kb tfgetS(), clear things for parent loop. */
915             FD_ZERO(&active);
916             FD_ZERO(&connected);
917 	    /* In case the dreaded solaris select bug caused tf to remove stdin
918 	     * from readers, user will probably panic and hit ^C, so we add
919 	     * stdin back to readers, and recover. */
920 	    FD_SET(STDIN_FILENO, &readers);
921 
922         } else {
923             if (count == 0) {
924                 /* select() must have exited due to timeout. */
925                 do_refresh();
926             }
927 
928             /* check for user input */
929             if (pending_input || FD_ISSET(STDIN_FILENO, &active)) {
930                 if (FD_ISSET(STDIN_FILENO, &active)) count--;
931                 do_refresh();
932                 if (!handle_keyboard_input(FD_ISSET(STDIN_FILENO, &active))) {
933                     /* input is at EOF, stop reading it */
934                     FD_CLR(STDIN_FILENO, &readers);
935                 }
936             }
937 
938             /* Check for socket completion/activity.  We pick up where we
939              * left off last time, so sockets near the end of the list aren't
940              * starved.  We stop when we've gone through the list once, or
941              * when we've received a lot of data (so spammy sockets don't
942              * degrade interactive response too much).
943              */
944             if (hsock) {
945                 received = 0;
946                 if (!sock) sock = hsock;
947                 stopsock = sock;
948 		/* note: count may have been zeroed by nested main_loop */
949                 while (count > 0 || socks_with_lines > 0 ||
950 		    prompt_timeout.tv_sec > 0)
951 		{
952                     xsock = sock;
953                     if (sock->constate >= SS_OPEN) {
954                         /* do nothing */
955                     } else if (FD_ISSET(xsock->fd, &connected)) {
956                         count--;
957                         establish(xsock);
958                     } else if (FD_ISSET(xsock->fd, &active)) {
959                         count--;
960                         if (xsock->constate == SS_RESOLVING) {
961                             openconn(xsock);
962                         } else if (xsock->constate == SS_CONNECTING) {
963                             establish(xsock);
964                         } else if (xsock == fsock || background) {
965                             received += handle_socket_input(NULL, 0, NULL);
966                         } else {
967                             FD_CLR(xsock->fd, &readers);
968                         }
969                     }
970 		    if (xsock->queue.list.head)
971 			handle_socket_lines();
972 
973 		    /* If there's a partial line that's past prompt_timeout,
974 		     * make it a prompt. */
975 		    if (xsock->prompt_timeout.tv_sec) {
976 			gettime(&now);
977 			if (tvcmp(&xsock->prompt_timeout, &now) < 0) {
978 			    handle_implicit_prompt();
979 			}
980 		    }
981 
982                     sock = sock->next ? sock->next : hsock;
983 		    if (sock == stopsock || received >= SPAM) break;
984                 }
985 
986                 /* fsock and/or xsock may have changed during loop above. */
987                 xsock = fsock;
988 
989 		if (prompt_timeout.tv_sec > 0) {
990 		    /* reset global prompt timeout */
991 		    Sock *psock;
992 		    prompt_timeout = tvzero;
993 		    for (psock = hsock; psock; psock = psock->next) {
994 			schedule_prompt(psock);
995 		    }
996 		}
997             }
998 
999 #if !NO_PROCESS
1000             /* other active fds must be from command /quotes. */
1001             if (count) gettime(&proctime);
1002 #endif
1003         }
1004 
1005         if (pending_line && read_depth) {    /* end of tf read() */
1006             pending_line = FALSE;
1007             break;
1008         }
1009 
1010 #if 0
1011         if (fsock && fsock->constate >= SS_ZOMBIE && auto_fg &&
1012 	    !(fsock->world->screen->nnew || fsock->queue.list.head))
1013 	{
1014             fg_live_sock();
1015         }
1016 #endif
1017 
1018         /* garbage collection */
1019         if (depth == 1) {
1020             if (sock && sock->constate == SS_DEAD) sock = NULL;
1021             if (dead_socks) nuke_dead_socks(); /* at end in case of quitdone */
1022             nuke_dead_macros();
1023             nuke_dead_procs();
1024         }
1025     }
1026 
1027     /* end of loop */
1028     if (!--depth) {
1029 	fsock = NULL;
1030 	xsock = NULL;
1031         while (hsock) nukesock(hsock);
1032 #if HAVE_SSL
1033 	SSL_CTX_free(ssl_ctx);
1034 #endif
1035     }
1036 
1037     /* If exiting recursive main_loop, count, active, and connected in the
1038      * parent main_loop are invalid.  Set count to 0 to indicate that. */
1039     count = 0;
1040 }
1041 
sockecho(void)1042 int sockecho(void)
1043 {
1044     return !xsock || (xsock && !TELOPT(xsock, them, TN_ECHO));
1045 }
1046 
close_all(void)1047 void close_all(void)
1048 {
1049     while (nfds > 3)
1050 	close(--nfds);
1051 }
1052 
is_active(int fd)1053 int is_active(int fd)
1054 {
1055     return FD_ISSET(fd, &active);
1056 }
1057 
readers_clear(int fd)1058 void readers_clear(int fd)
1059 {
1060     FD_CLR(fd, &readers);
1061 }
1062 
readers_set(int fd)1063 void readers_set(int fd)
1064 {
1065     FD_SET(fd, &readers);
1066     if (fd >= nfds) nfds = fd + 1;
1067 }
1068 
tog_bg(Var * var)1069 int tog_bg(Var *var)
1070 {
1071     Sock *sock;
1072     if (background)
1073         for (sock = hsock; sock; sock = sock->next)
1074             if (sock->constate == SS_CONNECTED)
1075                 FD_SET(sock->fd, &readers);
1076     return 1;
1077 }
1078 
tog_keepalive(Var * var)1079 int tog_keepalive(Var *var)
1080 {
1081     Sock *sock;
1082     int flags;
1083 
1084     flags = keepalive;
1085     for (sock = hsock; sock; sock = sock->next) {
1086 	if (sock->constate != SS_CONNECTED) continue;
1087 	if (setsockopt(sock->fd, SOL_SOCKET, SO_KEEPALIVE, (void*)&flags,
1088 	    sizeof(flags)) < 0)
1089 	{
1090 	    tf_wprintf("setsockopt KEEPALIVE: %s", strerror(errno));
1091 	}
1092     }
1093     return 1;
1094 }
1095 
1096 /* get name of foreground world */
fgname(void)1097 const char *fgname(void)
1098 {
1099     return fsock ? fsock->world->name : NULL;
1100 }
1101 
1102 /* get current operational world */
xworld(void)1103 World *xworld(void)
1104 {
1105     return xsock ? xsock->world : NULL;
1106 }
1107 
xsock_is_fg(void)1108 int xsock_is_fg(void)
1109 {
1110     return xsock == fsock;
1111 }
1112 
have_active_socks(void)1113 int have_active_socks(void)
1114 {
1115     Sock *sock;
1116 
1117     for (sock = hsock; sock; sock = sock->next) {
1118 	if (sock->world->screen->nnew || sock->queue.list.head)
1119 	    return 1;
1120     }
1121     return 0;
1122 }
1123 
1124 /* set alert_id on xsock, so fg_sock can decide whether to clear alert */
xsock_alert_id(void)1125 void xsock_alert_id(void)
1126 {
1127     if (xsock)
1128 	xsock->alert_id = alert_id;
1129 }
1130 
socktime(const char * name,int dir)1131 struct timeval *socktime(const char *name, int dir)
1132 {
1133     Sock *sock;
1134     sock = *name ? find_sock(name) : xsock;
1135     if (!sock) return NULL;
1136     return &sock->time[dir];
1137 }
1138 
find_sock(const char * name)1139 static Sock *find_sock(const char *name)
1140 {
1141     Sock *sock;
1142 
1143     /* It is possible to (briefly) have multiple sockets with the same name,
1144      * if at most one is alive.  The alive socket is the most interesting,
1145      * and it will be closer to the tail, so we search backwards.
1146      */
1147     for (sock = tsock; sock; sock = sock->prev)
1148         if (sock->world && cstrcmp(sock->world->name, name) == 0)
1149             return sock;
1150     return NULL;
1151 }
1152 
1153 /* load macro file for a world */
wload(World * w)1154 static void wload(World *w)
1155 {
1156     const char *mfile;
1157     if (restriction >= RESTRICT_FILE) return;
1158     if ((mfile = world_mfile(w)))
1159         do_file_load(mfile, FALSE, NULL);
1160 }
1161 
world_hook(const char * fmt,const char * name)1162 int world_hook(const char *fmt, const char *name)
1163 {
1164     return do_hook(H_WORLD, virtscreen ? NULL : fmt, "%s",
1165 	name ? name : "");
1166 }
1167 
1168 /* bring a socket into the foreground */
fg_sock(Sock * sock,int quiet)1169 static int fg_sock(Sock *sock, int quiet)
1170 {
1171     static int depth = 0;
1172 
1173     if (depth) {
1174         eprintf("illegal reentry");
1175         return 0;
1176     }
1177 
1178     if (sockecho() != (!sock || !TELOPT(sock, them, TN_ECHO)))
1179         set_refresh_pending(REF_LOGICAL);
1180 
1181     xsock = sock;
1182     if (sock == fsock) return 2;  /* already there */
1183 
1184     if (fsock) {                          /* the socket being backgrounded... */
1185 	/* ...has new text */
1186         if (fsock->world->screen->nnew || fsock->queue.list.head) {
1187 	    fsock->world->screen->active = 1;
1188             ++active_count;
1189             update_status_field(NULL, STAT_ACTIVE);
1190 	/* ...is dead, with all text seen */
1191         } else if (fsock->constate == SS_ZOMBIE) {
1192             fsock->constate = SS_DEAD;
1193 	    dead_socks++;
1194 	}
1195     }
1196     fsock = sock;
1197     depth++;
1198 
1199     if (!virtscreen) update_status_field(NULL, STAT_WORLD);
1200     hide_screen(NULL);
1201 
1202     if (sock) {
1203 	if (sock->alert_id == alert_id) {
1204 	    clear_alert();
1205 	    sock->alert_id = 0;
1206 	}
1207 	if (sock->constate == SS_CONNECTED)
1208 	    FD_SET(sock->fd, &readers);
1209         if (sock->world->screen->active) {
1210 	    sock->world->screen->active = 0;
1211             --active_count;
1212             update_status_field(NULL, STAT_ACTIVE);
1213         }
1214         fg_screen = sock->world->screen;
1215 	unhide_screen(fg_screen); /* must do before hook which might oflush */
1216         world_hook((sock->constate >= SS_ZOMBIE) ?
1217             "---- World %s (dead) ----" : "---- World %s ----",
1218            sock->world->name);
1219 	switch_screen(quiet || !bg_output);
1220         tog_lp(NULL);
1221         update_prompt(sock->prompt, 1);
1222         if (sockmload) wload(sock->world);
1223     } else {
1224         fg_screen = default_screen;
1225 	unhide_screen(fg_screen);
1226         world_hook("---- No world ----", NULL);
1227 	switch_screen(quiet || !bg_output);
1228         update_prompt(NULL, 1);
1229     }
1230     depth--;
1231     return 1;
1232 }
1233 
handle_fg_command(String * args,int offset)1234 struct Value *handle_fg_command(String *args, int offset)
1235 {
1236     int opt, nosock = FALSE, noerr = FALSE, quiet = FALSE;
1237     int num = 0;
1238     ValueUnion uval;
1239     Sock *sock;
1240 
1241     startopt(CS(args), "nlqs<>c#");
1242     while ((opt = nextopt(NULL, &uval, NULL, &offset))) {
1243         switch (opt) {
1244         case 'n':  nosock = TRUE;  break;
1245         case 's':  noerr = TRUE;  break;
1246         case 'l':  break;  /* accepted and ignored */
1247         case 'q':  quiet = TRUE; break;
1248         case '<':  num = -1;  break;
1249         case '>':  num =  1;  break;
1250         case 'c':  num = uval.ival; break;
1251         default:   return shareval(val_zero);
1252         }
1253     }
1254 
1255     if (nosock) {
1256         return newint(fg_sock(NULL, quiet));
1257 
1258     } else if (num) {
1259         Sock *stop;
1260         if (!hsock) return shareval(val_zero);
1261         stop = sock = (fsock ? fsock : hsock);
1262         do {
1263 	    sock = (num > 0) ?
1264 		(sock->next ? sock->next : hsock) :
1265 		(sock->prev ? sock->prev : tsock);
1266 	    num += (num<0) ? 1 : -1;
1267         } while (num && sock != stop);
1268         return newint(fg_sock(sock, quiet));
1269     }
1270 
1271     sock = (!(args->len - offset)) ? hsock : find_sock(args->data + offset);
1272     if (!sock) {
1273         if (!noerr) eprintf("no socket named '%s'", args->data + offset);
1274         return shareval(val_zero);
1275     }
1276     return newint(fg_sock(sock, quiet));
1277 }
1278 
1279 /* openworld
1280  * If (name && port), they are used as hostname and port number.
1281  * If (!port), name is used as the name of a world.  A NULL or empty name
1282  * corresponds to the first defined world.  A NULL name should be used for
1283  * the initial automatic connection, an empty name should be used for any
1284  * other unspecified connection.
1285  */
openworld(const char * name,const char * port,int flags)1286 int openworld(const char *name, const char *port, int flags)
1287 {
1288     World *world = NULL;
1289 
1290     if (!(flags & (CONN_FG | CONN_BG)))
1291 	flags |= (xsock == fsock) ? CONN_FG : CONN_BG;
1292     xsock = NULL;
1293     if (!port) {
1294         world = find_world(name);
1295         if (!world) {
1296             if (name) {
1297 		/* not H_CONFAIL (it needs a Sock, we haven't made one yet) */
1298                 eprintf("%s: %s",
1299                     *name ? name : "default world", "no such world");
1300             } else {
1301                 world_hook("---- No world ----", NULL);
1302 	    }
1303 	}
1304     } else {
1305         if (restriction >= RESTRICT_WORLD)
1306             eprintf("arbitrary connections restricted");
1307         else {
1308             world = new_world(NULL, "", name, port, "", "", "",
1309 		WORLD_TEMP | ((flags & CONN_SSL) ? WORLD_SSL : 0), "");
1310         }
1311     }
1312 
1313     return world ? opensock(world, flags) : 0;
1314 }
1315 
opensock(World * world,int flags)1316 static int opensock(World *world, int flags)
1317 {
1318     int gai_err;
1319     const char *what;
1320 
1321     if (world->sock) {
1322         if (world->sock->constate < SS_ZOMBIE) {
1323             eprintf("socket to %s already exists", world->name);
1324             return 0;
1325         }
1326         /* recycle existing Sock */
1327 	if (world->sock->constate == SS_DEAD)
1328 	    dead_socks--;
1329         xsock = world->sock;
1330 #if HAVE_SSL
1331 	if (xsock->ssl) {
1332 	    SSL_free(xsock->ssl); /* killsock() closed it, but didn't free it */
1333 	    xsock->ssl = NULL;
1334 	}
1335 #endif
1336 
1337     } else {
1338         /* create and initialize new Sock */
1339         if (!(xsock = world->sock = (Sock *) MALLOC(sizeof(struct Sock)))) {
1340             eprintf("opensock: not enough memory");
1341             return 0;
1342         }
1343         if (!world->screen)
1344             world->screen = new_screen(hist_getsize(world->history));
1345         xsock->world = world;
1346         xsock->prev = tsock;
1347         tsock = *(tsock ? &tsock->next : &hsock) = xsock;
1348         xsock->prompt = NULL;
1349 	xsock->prompt_timeout = tvzero;
1350         xsock->next = NULL;
1351 	xsock->myhost = NULL;
1352 	xsock->myaddr = NULL;
1353 	xsock->addrs = NULL;
1354 	xsock->addr = NULL;
1355 #if HAVE_SSL
1356 	xsock->ssl = NULL;
1357 #endif
1358     }
1359     Stringninit(xsock->buffer, 80);  /* data must be allocated */
1360     Stringninit(xsock->subbuffer, 1);
1361     init_queue(&xsock->queue);
1362     xsock->host = NULL;
1363     xsock->port = NULL;
1364     xsock->ttype = -1;
1365 #if WIDECHAR
1366 	 Stringninit(xsock->incomingposttelnet, 1);
1367 	 /* TODO: Better error handling, /addworld charset setting. */
1368     UErrorCode uerr = U_ZERO_ERROR;
1369     xsock->incomingfsm = ucnv_open(world->charset, &uerr);
1370     if (U_FAILURE(uerr))
1371         core("TN_CHARSET: Could not create UConverter.", __FILE__, __LINE__, 0);
1372 #endif
1373     xsock->fd = -1;
1374     xsock->pid = -1;
1375     xsock->fsastate = '\0';
1376     xsock->substate = '\0';
1377     xsock->attrs = 0;
1378     xsock->prepromptattrs = 0;
1379     xsock->alert_id = 0;
1380 #if HAVE_MCCP
1381     xsock->zstream = NULL;
1382 #endif
1383     VEC_ZERO(&xsock->tn_them);
1384     VEC_ZERO(&xsock->tn_them_tog);
1385     VEC_ZERO(&xsock->tn_us);
1386     VEC_ZERO(&xsock->tn_us_tog);
1387     xsock->constate = SS_NEW;
1388     xsock->flags = 0;
1389     gettime(&xsock->time[SOCK_SEND]);
1390     xsock->time[SOCK_RECV] = xsock->time[SOCK_SEND];
1391 
1392     if ((flags & CONN_QUIETLOGIN) && (flags & CONN_AUTOLOGIN) &&
1393 	world_character(world))
1394     {
1395 	xsock->numquiet = MAXQUIET;
1396     } else {
1397 	xsock->numquiet = 0;
1398     }
1399 
1400     if (flags & CONN_FG)
1401 	fg_sock(xsock, FALSE); /* XXX 2nd arg??? */
1402 
1403     if (flags & CONN_AUTOLOGIN) xsock->flags |= SOCKLOGIN;
1404     if (world->flags & WORLD_ECHO) xsock->flags |= SOCKECHO;
1405     if ((flags & CONN_SSL) || (world->flags & WORLD_SSL)) {
1406 #if HAVE_SSL
1407 	init_ssl();
1408 	// Note: set_verify() needs to b ecalled *before* SSL_new()
1409     	SSL_CTX_set_verify(ssl_ctx, SSL_VERIFY_PEER, ssl_verify_callback);
1410 	xsock->ssl = SSL_new(ssl_ctx);
1411 	SSL_CTX_set_verify_depth(ssl_ctx, ssl_depth);
1412 	ssl_mydata_index = SSL_get_ex_new_index(0, "ssl_mydata index",
1413 		NULL, NULL, NULL);
1414 	ssl_options.verify_depth = ssl_depth;
1415 	ssl_options.verbose_mode = ssl_verbose;
1416 	ssl_options.always_continue = ssl_continue;
1417 	SSL_set_ex_data(xsock->ssl, ssl_mydata_index, &ssl_options);
1418 #if OPENSSL_VERSION_NUMBER >= 0x1000200fL
1419 	X509_VERIFY_PARAM *param = SSL_get0_param(xsock->ssl);
1420 	X509_VERIFY_PARAM_set_hostflags(param,
1421 		X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS);
1422 	X509_VERIFY_PARAM_set1_host(param, xsock->world->host, 0);
1423 #endif
1424 #else
1425         CONFAIL(xsock, "ssl", "not supported");
1426 #endif
1427     }
1428 
1429     if (!world->host) {
1430 	/* opening a connectionless socket */
1431         xsock->constate = SS_OPEN;
1432         return establish(xsock);
1433     } else if (!(world->flags & WORLD_NOPROXY) && proxy_host && *proxy_host) {
1434 	/* open a connection through a proxy */
1435         xsock->flags |= SOCKPROXY;
1436         xsock->host = STRDUP(proxy_host);
1437         xsock->port = (proxy_port && *proxy_port) ? proxy_port : "23";
1438         xsock->port = STRDUP(xsock->port);
1439     } else {
1440 	/* open a connection directly */
1441         xsock->host = STRDUP(world->host);
1442         xsock->port = STRDUP(world->port);
1443     }
1444 
1445     xsock->flags |= SOCKMAYTELNET;
1446 
1447     if (world->myhost && *world->myhost)
1448 	xsock->myhost = STRDUP(world->myhost);
1449     else if (tfhost)
1450 	xsock->myhost = STRDUP(tfhost);
1451     else
1452 	xsock->myhost = NULL;
1453 
1454     if (xsock->myhost) {
1455 	/* We don't bother with nonblocking:  this feature is rarely used,
1456 	 * and the address should be numeric or resolvable locally (quickly)
1457 	 * anyway, so it's not worth the complications of nonblocking. */
1458 	struct addrinfo hints;
1459 	int err;
1460 	memset(&hints, 0, sizeof(hints));
1461 	hints.ai_family = PF_UNSPEC;
1462 	hints.ai_socktype = SOCK_STREAM;
1463 	err = getaddrinfo(xsock->myhost, NULL, &hints, &xsock->myaddr);
1464 
1465 	if (err) {
1466 	    CONFAIL(xsock, xsock->myhost, gai_strerror(err));
1467 	    killsock(xsock);  /* can't nukesock(), this Sock may be recycled. */
1468 	    return 0;
1469 	}
1470     }
1471 
1472     xsock->constate = SS_RESOLVING;
1473     xsock->fd = get_host_address(xsock, &what, &gai_err);
1474     if (xsock->fd == 0) {
1475         /* The name lookup succeeded */
1476         xsock->constate = SS_RESOLVED;
1477 	xsock->addr = xsock->addrs;
1478         return openconn(xsock);
1479 #ifdef NONBLOCKING_GETHOST
1480     } else if (xsock->fd > 0) {
1481         /* The name lookup is pending.  We wait for it for a fraction of a
1482          * second here so "relatively fast" looks "immediate" to the user.
1483          */
1484         fd_set readable;
1485         struct timeval tv;
1486         FD_ZERO(&readable);
1487         FD_SET(xsock->fd, &readable);
1488         tv.tv_sec = 0;
1489         tv.tv_usec = CONN_WAIT;
1490         if (select(xsock->fd + 1, &readable, NULL, NULL, &tv) > 0) {
1491             /* The lookup completed. */
1492             return openconn(xsock);
1493         }
1494         /* select() returned 0, or -1 and errno==EINTR.  Either way, the
1495          * lookup needs more time.  So we add the fd to the set being
1496          * watched by main_loop(), and don't block here any longer.
1497          */
1498         readers_set(xsock->fd);
1499         do_hook(H_PENDING, "%% Hostname lookup for %s in progress.", "%s",
1500             xsock->world->name);
1501         return 2;
1502 #endif /* NONBLOCKING_GETHOST */
1503     } else {
1504         /* The name lookup failed */
1505         /* Note, some compilers can't handle (herr ? hsterror() : literal) */
1506         if (what)
1507             CONFAIL(xsock, what, strerror(errno));
1508         else if (gai_err)
1509             CONFAILHP(xsock, gai_strerror(gai_err));
1510         else
1511             CONFAILHP(xsock, "name lookup failed");
1512         killsock(xsock);  /* can't nukesock(), this may be a recycled Sock. */
1513         return 0;
1514     }
1515 }
1516 
1517 
printai(struct addrinfo * ai,const char * fmt_hp)1518 static const char *printai(struct addrinfo *ai, const char *fmt_hp)
1519 {
1520     static char buf[1024];
1521     static char hostbuf[INET6_ADDRSTRLEN+1];
1522     const void *hostaddr = NULL;
1523     unsigned short port = 0;
1524     const char *host = NULL;
1525 
1526     if (!fmt_hp) fmt_hp = "%s %d";
1527 
1528     switch (ai->ai_family) {
1529 	case AF_INET:
1530 	    hostaddr = &((struct sockaddr_in*)ai->ai_addr)->sin_addr;
1531 	    port = ((struct sockaddr_in*)ai->ai_addr)->sin_port;
1532 	    host = inet_ntoa(*(struct in_addr*)hostaddr);
1533 	    break;
1534 #if ENABLE_INET6
1535 	case AF_INET6:
1536 	    hostaddr = &((struct sockaddr_in6*)ai->ai_addr)->sin6_addr;
1537 	    port = ((struct sockaddr_in6*)ai->ai_addr)->sin6_port;
1538 	    host = inet_ntop(ai->ai_family, hostaddr, hostbuf, sizeof(hostbuf));
1539 	    break;
1540 #endif
1541     }
1542     sprintf(buf, port ? fmt_hp : "%s", host ? host : "?", ntohs(port));
1543     return buf;
1544 }
1545 
ai_connect(int s,struct addrinfo * ai)1546 static inline int ai_connect(int s, struct addrinfo *ai)
1547 {
1548     do_hook(H_PENDING, "%% Trying to connect to %s: %s.", "%s %s",
1549 	xsock->world->name, printai(ai, NULL));
1550     return connect(s, ai->ai_addr, ai->ai_addrlen);
1551 }
1552 
setupnextconn(Sock * sock)1553 static void setupnextconn(Sock *sock)
1554 {
1555     struct addrinfo *ai, *next = sock->addr;
1556 
1557     if (sock->fd >= 0)
1558 	close(sock->fd);
1559 retry:
1560     next = next->ai_next;
1561     /* if next address is a duplicate of one we've already done, skip it */
1562     for (ai = sock->addrs; next && ai != next; ai = ai->ai_next) {
1563 	if (memcmp(ai->ai_addr, next->ai_addr, ai->ai_addrlen) == 0) {
1564 	    goto retry;
1565 	}
1566     }
1567     sock->addr = next;
1568 }
1569 
1570 /* If there are more addresses to try, hook ICONFAIL and try the next;
1571  * otherwise, hook CONFAIL and give up. */
ICONFAIL(Sock * sock,const char * what,const char * why)1572 static int ICONFAIL(Sock *sock, const char *what, const char *why)
1573 {
1574     setupnextconn(sock);
1575 
1576     if (sock->addr) {
1577 	do_hook(H_ICONFAIL, ICONFAIL_fmt, "%s %s: %s",
1578 	    (sock)->world->name, (what), (why));
1579 	oflush();
1580 	return openconn(sock);
1581     }
1582     do_hook(H_CONFAIL, "%% Connection to %s failed: %s: %s", "%s %s: %s",
1583 	(sock)->world->name, (what), (why));
1584     oflush();
1585     killsock(sock);
1586     return 0;
1587 }
1588 
openconn(Sock * sock)1589 static int openconn(Sock *sock)
1590 {
1591     int flags;
1592 
1593     xsock = sock;
1594 #ifdef NONBLOCKING_GETHOST
1595     if (xsock->constate == SS_RESOLVING) {
1596 	nbgai_hdr_t info = { 0, 0 };
1597 	struct addrinfo *ai;
1598         FD_CLR(xsock->fd, &readers);
1599         if (read(xsock->fd, &info, sizeof(info)) < 0 || info.err != 0) {
1600             if (!info.err)
1601                 CONFAIL(xsock, "read", strerror(errno));
1602             else
1603 		CONFAILHP(xsock, gai_strerror(info.err));
1604             close(xsock->fd);
1605             xsock->fd = -1;
1606 # ifdef PLATFORM_UNIX
1607 	    if (xsock->pid >= 0)
1608 		if (waitpid(xsock->pid, NULL, 0) < 0)
1609 		    tfprintf(tferr, "waitpid %ld: %s", xsock->pid, strerror(errno));
1610 	    xsock->pid = -1;
1611 # endif /* PLATFORM_UNIX */
1612             killsock(xsock);
1613             return 0;
1614         }
1615 	if (info.size <= 0) { /* shouldn't happen */
1616 	    xsock->addrs = NULL;
1617 	} else {
1618 	    xsock->addrs = XMALLOC(info.size);
1619 	    read(xsock->fd, (char*)xsock->addrs, info.size);
1620 	}
1621         close(xsock->fd);
1622 # ifdef PLATFORM_UNIX
1623         if (xsock->pid >= 0)
1624             if (waitpid(xsock->pid, NULL, 0) < 0)
1625                tfprintf(tferr, "waitpid: %ld: %s", xsock->pid, strerror(errno));
1626         xsock->pid = -1;
1627 # endif /* PLATFORM_UNIX */
1628         xsock->constate = SS_RESOLVED;
1629 	for (ai = xsock->addrs; ai; ai = ai->ai_next) {
1630 	    ai->ai_addr = (struct sockaddr*)((char*)ai + sizeof(*ai));
1631 	    if (ai->ai_next != 0) {
1632 		ai->ai_next =
1633 		    (struct addrinfo*)((char*)ai->ai_addr + ROUND_UP_LENGTH(ai->ai_addrlen));
1634 	    }
1635 	}
1636 	xsock->addr = xsock->addrs;
1637     }
1638 #endif /* NONBLOCKING_GETHOST */
1639 
1640 #if 0
1641     /* Jump back here if we start a nonblocking connect and then discover
1642      * that the platform has a broken read() or select().
1643      */
1644     retry:
1645 #endif
1646 
1647     if (!xsock->addr) {
1648 	CONFAILHP(xsock, "no usable addresses");
1649 	killsock(xsock);
1650 	return 0;
1651     }
1652 
1653     xsock->fd = socket(xsock->addr->ai_family, xsock->addr->ai_socktype,
1654 	xsock->addr->ai_protocol);
1655     if (xsock->fd < 0) {
1656 	if (errno == EPROTONOSUPPORT || errno == EAFNOSUPPORT)
1657 	    return ICONFAIL(xsock, "socket", strerror(errno));
1658         CONFAIL(xsock, "socket", strerror(errno));
1659         killsock(xsock);
1660         return 0;
1661     }
1662 
1663     if (xsock->myaddr && bind(xsock->fd, xsock->myaddr->ai_addr,
1664 	xsock->myaddr->ai_addrlen) < 0)
1665     {
1666         CONFAIL(xsock, printai(xsock->myaddr, NULL), strerror(errno));
1667         killsock(xsock);
1668         return 0;
1669     }
1670 
1671 #if HAVE_SSL
1672     if (xsock->ssl && SSL_set_fd(xsock->ssl, xsock->fd) <= 0) {
1673         CONFAIL(xsock, "SSL", ERR_error_string(ERR_get_error(), NULL));
1674         killsock(xsock);
1675         return 0;
1676     }
1677 #endif
1678 
1679     if (xsock->fd >= nfds) nfds = xsock->fd + 1;
1680 
1681     if (!TF_NONBLOCK) {
1682         set_var_by_id(VAR_async_conn, 0);
1683     } else if (async_conn) {
1684         /* note: 3rd arg to fcntl() is optional on Unix, but required by OS/2 */
1685         if ((flags = fcntl(xsock->fd, F_GETFL, 0)) < 0) {
1686             operror("Can't make socket nonblocking: F_GETFL fcntl");
1687             set_var_by_id(VAR_async_conn, 0);
1688         } else if ((fcntl(xsock->fd, F_SETFL, flags | TF_NONBLOCK)) < 0) {
1689             operror("Can't make socket nonblocking: F_SETFL fcntl");
1690             set_var_by_id(VAR_async_conn, 0);
1691         }
1692     }
1693 
1694     if (keepalive) {
1695 	flags = 1;
1696 	if (setsockopt(xsock->fd, SOL_SOCKET, SO_KEEPALIVE, (void*)&flags,
1697 	    sizeof(flags)) < 0)
1698 	{
1699 	    tf_wprintf("setsockopt KEEPALIVE: %s", strerror(errno));
1700 	}
1701     }
1702 
1703     xsock->constate = SS_CONNECTING;
1704     if (ai_connect(xsock->fd, xsock->addr) == 0) {
1705         /* The connection completed successfully. */
1706         xsock->constate = SS_CONNECTED;
1707         return establish(xsock);
1708 
1709 #ifdef EINPROGRESS
1710     } else if (errno == EINPROGRESS) {
1711         /* The connection needs more time.  It will select() as writable when
1712          * it has connected, or readable when it has failed.  We select() it
1713          * briefly here so "fast" looks synchronous to the user.
1714          */
1715         fd_set writeable;
1716         struct timeval tv;
1717         FD_ZERO(&writeable);
1718         FD_SET(xsock->fd, &writeable);
1719         tv.tv_sec = 0;
1720         tv.tv_usec = CONN_WAIT;
1721         if (select(xsock->fd + 1, NULL, &writeable, NULL, &tv) > 0) {
1722             /* The connection completed. */
1723             return establish(xsock);
1724         }
1725         /* select() returned 0, or -1 and errno==EINTR.  Either way, the
1726          * connection needs more time.  So we add the fd to the set being
1727          * watched by main_loop(), and don't block here any longer.
1728          */
1729         FD_SET(xsock->fd, &writers);
1730         FD_SET(xsock->fd, &readers);
1731         return 2;
1732 #endif /* EINPROGRESS */
1733 
1734 #if 0  /* this can cause problems on nonbuggy systems, so screw the sysv bug */
1735     } else if (can_nonblock && (errno == EAGAIN
1736 # ifdef EWOULDBLOCK
1737                                                 || errno == EWOULDBLOCK
1738 # endif
1739                                                                        )) {
1740         /* A bug in SVR4.2 causes nonblocking connect() to (sometimes?)
1741          * incorrectly fail with EAGAIN.  The only thing we can do about
1742          * it is to try a blocking connect().
1743          */
1744         close(xsock->fd);
1745         can_nonblock = FALSE;
1746         goto retry; /* try again */
1747 #endif /* 0 */
1748     }
1749 
1750     /* The connection failed; try the next address. */
1751     return ICONFAIL_AI(xsock, strerror(errno));
1752 }
1753 
1754 #if !HAVE_GETADDRINFO
1755 /* Partial implementation of getaddrinfo():  returns a single address for an
1756  * IPv6 address OR IPv4 address OR a name that resolves to an IPv4 address.
1757  * Ignores hints except for AI_NUMERICHOST.  Port is optional.
1758  */
tfgetaddrinfo(const char * nodename,const char * port,const struct addrinfo * hints,struct addrinfo ** res)1759 static int tfgetaddrinfo(const char *nodename, const char *port,
1760     const struct addrinfo *hints, struct addrinfo **res)
1761 {
1762     struct servent *service;
1763     struct hostent *host;
1764     unsigned short portnum = 0, sa_len = 0;
1765     int err = 0;
1766     struct {
1767 	struct addrinfo ai;
1768 	union {
1769 	    struct sockaddr sa;
1770 	    struct sockaddr_in sin4;
1771 # if ENABLE_INET6
1772 	    struct sockaddr_in6 sin6;
1773 # endif
1774 	} sa;
1775     } *blob;
1776 
1777     blob = MALLOC(sizeof(*blob));
1778     if (!blob) return TF_EAI_MEMORY;
1779 
1780     /* translate/look up port */
1781     if (port) {
1782 	if (is_digit(*port)) {
1783 	    portnum = htons(atoi(port));
1784 # ifdef NETDB_H
1785 	} else if ((service = getservbyname(port, "tcp"))) {
1786 	    portnum = service->s_port;
1787 # endif
1788 	} else {
1789 	    err = TF_EAI_SERVICE;
1790 	    goto error;
1791 	}
1792     }
1793 
1794 # if ENABLE_INET6
1795     /* translate numeric IPv6 address */
1796     if (inet_pton(AF_INET6, nodename, &blob->sa.sin6.sin6_addr)) {
1797 	sa_len = sizeof(blob->sa.sin6);
1798 	blob->sa.sa.sa_family = PF_INET6;
1799 	blob->sa.sin6.sin6_port = portnum;
1800 	goto found;
1801     }
1802 # endif
1803 
1804     /* translate numeric IPv4 address */
1805 # if HAVE_INET_ATON
1806     if (inet_aton(nodename, &blob->sa.sin4.sin_addr))
1807 # elif !defined(dgux)
1808     /* Most versions of inet_addr() return a long. */
1809     blob->sa.sin4.sin_addr.s_addr = inet_addr(nodename);
1810     if (blob->sa.sin4.sin_addr.s_addr != INADDR_NONE)
1811 # else
1812     /* DGUX's inet_addr() returns a struct in_addr. */
1813     blob->sa.sin4.sin_addr.s_addr = inet_addr(nodename).s_addr;
1814     if (blob->sa.sin4.sin_addr.s_addr != INADDR_NONE)
1815 # endif /* HAVE_INET_ATON */
1816     {
1817 	sa_len = sizeof(blob->sa.sin4);
1818 	blob->sa.sa.sa_family = PF_INET;
1819 	blob->sa.sin4.sin_port = portnum;
1820         goto found;
1821     }
1822 
1823     if (hints->ai_flags & AI_NUMERICHOST) {
1824 	FREE(blob);
1825 	*res = NULL;
1826 	return TF_EAI_NODATA;
1827     }
1828 
1829     /* look up text address (IPv4 only) */
1830     host = gethostbyname(nodename);
1831     if (!host) {
1832 	err = h_errno;
1833 	goto error;
1834     }
1835     sa_len = sizeof(blob->sa.sin4);
1836     blob->sa.sa.sa_family = PF_INET;
1837     blob->sa.sin4.sin_port = portnum;
1838     memcpy((void *)&blob->sa.sin4.sin_addr, (void *)host->h_addr,
1839 	sizeof(blob->sa.sin4.sin_addr));
1840 
1841 found:
1842 # if HAVE_SOCKADDR_SA_LEN
1843     blob->sa.sa.sa_len = sa_len;
1844 # endif
1845     blob->ai.ai_family = blob->sa.sa.sa_family;
1846     blob->ai.ai_socktype = SOCK_STREAM;
1847     blob->ai.ai_protocol = IPPROTO_TCP;
1848     blob->ai.ai_addrlen = sa_len;
1849     blob->ai.ai_canonname = NULL;
1850     blob->ai.ai_addr = (struct sockaddr*)&blob->sa;
1851     blob->ai.ai_next = NULL;
1852     *res = &blob->ai;
1853     return 0;
1854 
1855 error:
1856     FREE(blob);
1857     return err;
1858 }
1859 #endif /* !HAVE_GETADDRINFO */
1860 
tffreeaddrinfo(struct addrinfo * ai)1861 static void tffreeaddrinfo(struct addrinfo *ai)
1862 {
1863     /* ai and all contents were allocated in single chunk by tfgetaddrinfo()
1864      * or completed nonblocking resolution in openconn() */
1865     FREE(ai);
1866 }
1867 
1868 /* Convert name or ip number string to a list of struct addrinfo.
1869  * Returns -1 for failure, 0 for success, or a positive file descriptor
1870  * connected to a pending name lookup process or thread.
1871  */
get_host_address(Sock * sock,const char ** what,int * errp)1872 static int get_host_address(Sock *sock, const char **what, int *errp)
1873 {
1874     struct addrinfo hints;
1875     memset(&hints, 0, sizeof(hints));
1876     hints.ai_family = PF_UNSPEC;
1877     hints.ai_socktype = SOCK_STREAM;
1878     hints.ai_flags = AI_NUMERICHOST;
1879 #if 0 /* AI_ADDRCONFIG is defined on FreeBSD 4.2, but causes an error in
1880 	 getaddrinfo() (this was fixed by 4.8).  It's not important to
1881 	 use the flag, so it's easier to not use it and avoid the problem. */
1882 # ifdef AI_ADDRCONFIG
1883     hints.ai_flags |= AI_ADDRCONFIG;
1884 # endif
1885 #endif
1886     *errp = getaddrinfo(sock->host, sock->port, &hints, &sock->addrs);
1887     *what = NULL;
1888     if (*errp == 0) return 0;
1889 
1890 #ifdef NONBLOCKING_GETHOST
1891     if (async_name) {
1892 	/* do nonblocking for non-numeric */
1893 	*errp = 0;
1894 	*what = NULL;
1895 	sock->flags |= SOCKALLOCADDRS;
1896 	return nonblocking_gethost(sock->host, sock->port, &sock->addrs,
1897 	    &sock->pid, what);
1898     } else
1899 #endif
1900     {
1901 	hints.ai_flags &= ~AI_NUMERICHOST;
1902 	*errp = getaddrinfo(sock->host, sock->port, &hints, &sock->addrs);
1903 	*what = NULL;
1904 	if (*errp == 0) return 0;
1905     }
1906     return -1;
1907 }
1908 
1909 #ifdef NETDB_H
1910 #ifdef NONBLOCKING_GETHOST
1911 
waitforhostname(int fd,const char * name,const char * port)1912 static void waitforhostname(int fd, const char *name, const char *port)
1913 {
1914     /* Uses writev() so the write is atomic, to avoid race condition between
1915      * writer and reader processes.  (Really, the reader should loop reading
1916      * until EOF.)
1917      */
1918     struct addrinfo *res, *ai;
1919     struct addrinfo hints;
1920     nbgai_hdr_t hdr;
1921 #define NIOV 1+2*16
1922     struct iovec iov[NIOV];
1923     int niov;
1924 
1925     memset(&hints, 0, sizeof(hints));
1926     hints.ai_family = PF_UNSPEC;
1927     hints.ai_socktype = SOCK_STREAM;
1928 
1929     hdr.err = getaddrinfo(name, port, &hints, &res);
1930 
1931     if (!hdr.err) {
1932 	hdr.size = 0;
1933 	iov[0].iov_base = (char*)&hdr;
1934 	iov[0].iov_len = sizeof(hdr);
1935 	niov = 1;
1936 	for (ai = res; ai && niov < NIOV; ai = ai->ai_next) {
1937 	    static const char zeros[ 8 ] = { 0, 0, 0, 0, 0, 0, 0, 0 };
1938 	    size_t padded = ROUND_UP_LENGTH(ai->ai_addrlen);
1939 	    hdr.size += sizeof(*ai) + padded;
1940 	    iov[niov].iov_base = (char*)ai;
1941 	    iov[niov].iov_len = sizeof(*ai);
1942 	    niov++;
1943 	    iov[niov].iov_base = (char*)ai->ai_addr;
1944 	    iov[niov].iov_len = ai->ai_addrlen;
1945 	    niov++;
1946 	    if (padded != ai->ai_addrlen) {
1947 		/* padding */
1948 		iov[niov].iov_base = (char*)zeros;
1949 		iov[niov].iov_len = padded - ai->ai_addrlen;
1950 		niov++;
1951 	    }
1952 	}
1953 	writev(fd, iov, niov);
1954 	if (res) freeaddrinfo(res);
1955     } else {
1956 	hdr.size = 0;
1957 	write(fd, &hdr, sizeof(hdr));
1958     }
1959     close(fd);
1960 }
1961 
1962 # ifdef PLATFORM_OS2
1963 typedef struct _threadpara {
1964     const char *hostname;
1965     const char *port;
1966     int   fd;
1967 } threadpara;
1968 
os2waitforhostname(threadpara * targs)1969 void os2waitforhostname(threadpara *targs)
1970 {
1971     waitforhostname(targs->fd, targs->hostname, targs->port);
1972     FREE(targs->hostname);
1973     FREE(targs->port);
1974     FREE(targs);
1975 }
1976 # endif /* PLATFORM_OS2 */
1977 
nonblocking_gethost(const char * name,const char * port,struct addrinfo ** res,pid_t * pidp,const char ** what)1978 static int nonblocking_gethost(const char *name, const char *port,
1979     struct addrinfo **res, pid_t *pidp, const char **what)
1980 {
1981     int fds[2];
1982     int err;
1983 
1984     *what = "pipe";
1985     if (pipe(fds) < 0) return -1;
1986 
1987 #ifdef PLATFORM_UNIX
1988     {
1989         *what = "fork";
1990         *pidp = fork();
1991         if (*pidp > 0) {          /* parent */
1992             close(fds[1]);
1993             return fds[0];
1994         } else if (*pidp == 0) {  /* child */
1995             close(fds[0]);
1996             waitforhostname(fds[1], name, port);
1997             exit(0);
1998         }
1999     }
2000 #endif
2001 #ifdef PLATFORM_OS2
2002     {
2003         threadpara *tpara;
2004 
2005         if ((tpara = XMALLOC(sizeof(threadpara)))) {
2006             setmode(fds[0],O_BINARY);
2007             setmode(fds[1],O_BINARY);
2008             tpara->fd = fds[1];
2009             tpara->hostname = STRDUP(name);
2010             tpara->port = STRDUP(port);
2011 
2012             /* BUG: gethostbyname() isn't threadsafe! */
2013             *what = "_beginthread";
2014             if (_beginthread(os2waitforhostname,NULL,0x8000,(void*)tpara) != -1)
2015                 return(fds[0]);
2016         }
2017     }
2018 #endif
2019 
2020     /* failed */
2021     err = errno;
2022     close(fds[0]);
2023     close(fds[1]);
2024     errno = err;
2025     return -1;
2026 }
2027 #endif /* NONBLOCKING_GETHOST */
2028 #endif /* NETDB_H */
2029 
2030 
2031 /* Establish a sock for which connect() has completed. */
establish(Sock * sock)2032 static int establish(Sock *sock)
2033 {
2034     xsock = sock;
2035 #if TF_NONBLOCK
2036     if (xsock->constate == SS_CONNECTING) {
2037         int err = 0, flags;
2038         socklen_t len = sizeof(err);
2039 
2040         /* Old Method 1: If read(fd, buf, 0) fails, the connect() failed, and
2041          * errno will explain why.  Problem: on some systems, a read() of
2042          * 0 bytes is always successful, even if socket is not connected.
2043          */
2044         /* Old Method 2: If a second connect() fails with EISCONN, the first
2045          * connect() worked.  On the slim chance that the first failed, but
2046          * the second worked, use that.  Otherwise, use getsockopt(SO_ERROR)
2047          * to find out why the first failed.  If SO_ERROR isn't available,
2048          * use read() to get errno.  This method works for all systems, as
2049          * well as SOCKS 4.2beta.  Problems: Some socket implementations
2050          * give the wrong errno; extra net traffic on failure.
2051          */
2052         /* CURRENT METHOD:  If possible, use getsockopt(SO_ERROR) to test for
2053          * an error.  This avoids the overhead of a second connect(), and the
2054          * possibility of getting the error value from the second connect()
2055          * (linux).  (Potential problem: it's possible that some systems
2056          * don't clear the SO_ERROR value for successful connect().)
2057          * If SO_ERROR is not available or we are using SOCKS, we try to read
2058          * 0 bytes.  If it fails, the connect() must have failed.  If it
2059          * succeeds, we can't know if it's because the connection really
2060          * succeeded, or the read() did a no-op for the 0 size, so we try a
2061          * second connect().  If the second connect() fails with EISCONN, the
2062          * first connect() worked.  If it works (unlikely), use it.  Otherwise,
2063          * use read() to get the errno.
2064          * Tested on:  Linux, HP-UX, Solaris, Solaris with SOCKS5...
2065          */
2066         /* Alternative: replace second connect() with getpeername(), and
2067          * check for ENOTCONN.  Disadvantage: doesn't work with SOCKS, etc.
2068          */
2069 
2070 #ifdef SO_ERROR
2071 # if !SOCKS
2072 #  define USE_SO_ERROR
2073 # endif
2074 #endif
2075 
2076 #ifdef USE_SO_ERROR
2077         if (getsockopt(xsock->fd, SOL_SOCKET, SO_ERROR, (void*)&err, &len) < 0)
2078         {
2079             return ICONFAIL(xsock, "getsockopt", strerror(errno));
2080         }
2081 
2082 #else
2083         {
2084             char ch;
2085             if (read(xsock->fd, &ch, 0) < 0) {
2086 		return ICONFAIL(xsock, "nonblocking connect/read", strerror(errno));
2087             } else if ((ai_connect(xsock->fd, xsock->addr) < 0) &&
2088                 errno != EISCONN)
2089             {
2090                 read(xsock->fd, &ch, 1);   /* must fail */
2091 		return ICONFAIL(xsock, "nonblocking connect 2/read", strerror(errno));
2092             }
2093         }
2094 #endif
2095         if (err != 0) {
2096 	    return ICONFAIL_AI(xsock, strerror(err));
2097         }
2098 
2099         /* connect() worked.  Clear the pending stuff, and get on with it. */
2100         xsock->constate = SS_CONNECTED;
2101         FD_CLR(xsock->fd, &writers);
2102 
2103         /* Turn off nonblocking (this should help on buggy systems). */
2104         /* note: 3rd arg to fcntl() is optional on Unix, but required by OS/2 */
2105         if ((flags = fcntl(xsock->fd, F_GETFL, 0)) >= 0)
2106             fcntl(xsock->fd, F_SETFL, flags & ~TF_NONBLOCK);
2107     }
2108 #endif /* TF_NONBLOCK */
2109 
2110     if (xsock->constate == SS_CONNECTED)
2111 	FD_SET(xsock->fd, &readers);
2112 
2113     /* hack: sockaddr_in.sin_port and sockaddr_in6.sin6_port coincide */
2114     if (xsock->addr &&
2115 	ntohs(((struct sockaddr_in*)xsock->addr->ai_addr)->sin_port) == 23)
2116 	    xsock->flags |= SOCKTELNET;
2117 
2118 #if HAVE_SSL
2119     if (xsock->ssl) {
2120 	int sslret;
2121 	sslret = SSL_connect(xsock->ssl);
2122 	if (sslret <= 0) {
2123 	    setupnextconn(xsock);
2124 	    ssl_io_err(xsock, sslret, xsock->addr ? H_ICONFAIL : H_CONFAIL);
2125 	    if (xsock->addr)
2126 		return openconn(xsock);
2127 	    killsock(xsock);
2128 	    return 0;
2129 	}
2130 	ssl_check_cert_verify(sock);
2131     }
2132 #endif
2133 
2134     /* atomicness ends here */
2135 
2136     if (xsock == fsock)   /* possible for a recycled zombie */
2137         update_status_field(NULL, STAT_WORLD);
2138 
2139     if (xsock->flags & SOCKTELNET)
2140         preferred_telnet_options();
2141 
2142     if (sock->flags & SOCKPROXY) {
2143         FREE(sock->host);
2144         FREE(sock->port);
2145         sock->host = STRDUP(sock->world->host);
2146         sock->port = STRDUP(sock->world->port);
2147         do_hook(H_PROXY, "", "%s", sock->world->name);
2148     }
2149 
2150     wload(sock->world);
2151 
2152     if (!(sock->flags & SOCKPROXY)) {
2153 #if HAVE_SSL
2154 	if (sock->ssl)
2155 	    do_hook(H_CONNECT, "%% Connected to %s using cipher %s.", "%s %s",
2156 		sock->world->name, SSL_get_cipher_name(sock->ssl));
2157 	else
2158 #endif
2159 	    do_hook(H_CONNECT, "%% Connected to %s.", "%s", sock->world->name);
2160 
2161         if (login && sock->flags & SOCKLOGIN) {
2162             if (world_character(sock->world) && world_pass(sock->world))
2163                 do_hook(H_LOGIN, NULL, "%s %s %s", sock->world->name,
2164                     world_character(sock->world), world_pass(sock->world));
2165             sock->flags &= ~SOCKLOGIN;
2166         }
2167     }
2168 
2169     return 1;
2170 }
2171 
2172 #if HAVE_SSL
ssl_check_cert_verify(Sock * sock)2173 static int ssl_check_cert_verify(Sock *sock)
2174 {
2175     int ret = 0;
2176     long result = SSL_get_verify_result(sock->ssl);
2177     if (result == X509_V_OK) {
2178 	/* The client sent a certificate which verified OK */
2179 	do_hook(H_PENDING, "%% SSL: cert verified: OK ret=%ld",
2180 		"%ld", result);
2181     }
2182     else {
2183 	do_hook(H_PENDING, "%% SSL: cert verify failed: ERROR err=%ld",
2184 		"%ld", result);
2185     }
2186     return ret;
2187 }
2188 #endif
2189 
2190 /* clear most of sock's fields, but leave it consistent and extant */
killsock(Sock * sock)2191 static void killsock(Sock *sock)
2192 {
2193     if (sock->constate >= SS_ZOMBIE) return;
2194 #if 0 /* There may be a disconnect hook AFTER this function... */
2195     if (sock == fsock || sock->queue.list.head || sock->world->screen->nnew) {
2196 	sock->constate = SS_ZOMBIE;
2197     } else {
2198 	sock->constate = SS_DEAD;
2199 	dead_socks++;
2200     }
2201 #else /* ... so we must unconditionally enter ZOMBIE state. */
2202     sock->constate = SS_ZOMBIE;
2203 #endif
2204     sock->fsastate = '\0';
2205     sock->attrs = 0;
2206     VEC_ZERO(&sock->tn_them);
2207     VEC_ZERO(&sock->tn_them_tog);
2208     VEC_ZERO(&sock->tn_us);
2209     VEC_ZERO(&sock->tn_us_tog);
2210     Stringfree(sock->buffer);
2211     Stringfree(sock->subbuffer);
2212 
2213     unprompt(sock, sock==fsock);
2214 
2215     if (sock->host) FREE(sock->host);
2216     if (sock->port) FREE(sock->port);
2217     if (sock->myhost) FREE(sock->myhost);
2218     sock->host = sock->port = sock->myhost = NULL;
2219 
2220     if (sock->addrs) {
2221 	if (sock->flags & SOCKALLOCADDRS)
2222 	    tffreeaddrinfo(sock->addrs);
2223 	else
2224 	    freeaddrinfo(sock->addrs);
2225 	sock->addrs = NULL;
2226     }
2227     if (sock->myaddr) {
2228 	freeaddrinfo(sock->myaddr);
2229 	sock->myaddr = NULL;
2230     }
2231 #if HAVE_SSL
2232     if (sock->ssl) {
2233 	SSL_shutdown(sock->ssl);
2234 	/* Don't SSL_free() yet: we still need to be able to use SSL_error() */
2235     }
2236 #endif
2237     if (sock->fd >= 0) {
2238         FD_CLR(sock->fd, &readers);
2239         FD_CLR(sock->fd, &writers);
2240         close(sock->fd);
2241         sock->fd = -1;
2242     }
2243 #if HAVE_MCCP
2244     if (sock->zstream) {
2245 	inflateEnd(sock->zstream);
2246 	FREE(sock->zstream);
2247     }
2248 #endif
2249 #ifdef NONBLOCKING_GETHOST
2250 # ifdef PLATFORM_UNIX
2251     if (sock->pid >= 0) {
2252         kill(sock->pid, SIGTERM);
2253         if (waitpid(sock->pid, NULL, 0) < 0)
2254             tfprintf(tferr, "waitpid: %ld: %s", sock->pid, strerror(errno));
2255         sock->pid = -1;
2256     }
2257 # endif /* PLATFORM_UNIX */
2258 #endif /* NONBLOCKING_GETHOST */
2259     if (sock == fsock)
2260 	update_status_field(NULL, STAT_WORLD);
2261 }
2262 
2263 /* nukesock
2264  * Remove socket from list and free memory.  Should only be called on a
2265  * Sock which is known to have no references other than the socket list.
2266  */
nukesock(Sock * sock)2267 static void nukesock(Sock *sock)
2268 {
2269     if (sock->queue.list.head) {
2270 	internal_error(__FILE__, __LINE__, "socket %s has unprocessed lines",
2271 	    !sock ? "!sock" :
2272 	    !sock->world ? "!sock->world" :
2273 	    sock->world->name);
2274 	socks_with_lines--;
2275     }
2276     if (sock == xsock) xsock = NULL;
2277     sock->world->sock = NULL;
2278     killsock(sock);
2279     *((sock == hsock) ? &hsock : &sock->prev->next) = sock->next;
2280     *((sock == tsock) ? &tsock : &sock->next->prev) = sock->prev;
2281     if (sock->world->screen->active) {
2282 	sock->world->screen->active = 0;
2283         --active_count;
2284         update_status_field(NULL, STAT_ACTIVE);
2285     }
2286     if (sock->world->flags & WORLD_TEMP) {
2287         nuke_world(sock->world);
2288         sock->world = NULL;
2289     }
2290 #if HAVE_SSL
2291     if (sock->ssl) {
2292 	SSL_free(sock->ssl);
2293 	sock->ssl = NULL;
2294     }
2295 #endif
2296     FREE(sock);
2297 }
2298 
2299 #if 0
2300 static void fg_live_sock(void)
2301 {
2302     /* If the fg sock is dead, find another sock to put in fg.  Since this
2303      * is called from main_loop(), xsock must be the same as fsock.  We must
2304      * keep it that way.  Note that a user hook in fg_sock() could kill the
2305      * new fg sock, so we must loop until the new fg sock stays alive.
2306      */
2307     while (fsock && (fsock->constate >= SS_ZOMBIE)) {
2308         for (xsock = hsock; xsock; xsock = xsock->next) {
2309             if (xsock->constate < SS_ZOMBIE)
2310 		break;
2311         }
2312         fg_sock(xsock, FALSE);
2313     }
2314 }
2315 #endif
2316 
2317 /* delete all dead sockets */
nuke_dead_socks(void)2318 static void nuke_dead_socks(void)
2319 {
2320     Sock *sock, *next;
2321 
2322     for (sock = hsock; sock; sock = next) {
2323         next = sock->next;
2324         if (sock->constate == SS_ZOMBIE) {
2325 	    if (sock->fd >= 0)
2326 		FD_CLR(sock->fd, &readers);
2327         } else if (sock->constate == SS_DEAD) {
2328             nukesock(sock);
2329             dead_socks--;
2330         }
2331     }
2332     if (quitdone && !hsock) quit_flag = 1;
2333 }
2334 
queue_socket_line(Sock * sock,const conString * line,int length,attr_t attr)2335 static void queue_socket_line(Sock *sock, const conString *line, int length,
2336     attr_t attr)
2337 {
2338     String *new;
2339     (new = StringnewM(NULL, length, 0, sock->world->md))->links++;
2340     SStringoncat(new, line, 0, length);
2341     new->attrs |= attr;
2342     gettime(&new->time);
2343     sock->time[SOCK_RECV] = new->time;
2344     new->attrs &= ~F_GAG; /* in case gagged line was passed via fake_recv() */
2345     if (!sock->queue.list.head)
2346 	socks_with_lines++;
2347     enqueue(&sock->queue, new);
2348 }
2349 
dc(Sock * s)2350 static void dc(Sock *s)
2351 {
2352     String *buffer = Stringnew(NULL, -1, 0);
2353     Sock *oldxsock = xsock;
2354     xsock = s;
2355 #if WIDECHAR
2356     inbound_decode_str(s->buffer, s->incomingposttelnet, s->incomingfsm, 1);
2357     handle_socket_input_queue_lines(xsock);
2358 #endif
2359     flushxsock();
2360     Sprintf(buffer, "%% Connection to %s closed.", s->world->name);
2361     world_output(s->world, CS(buffer));
2362     if (xsock != fsock) oputline(CS(buffer));
2363     zombiesock(xsock);
2364     xsock = oldxsock;
2365 }
2366 
2367 /* disconnect a socket */
handle_dc_command(String * args,int offset)2368 struct Value *handle_dc_command(String *args, int offset)
2369 {
2370     Sock *s;
2371 
2372     if (!(args->len - offset)) {
2373         if (!xsock) {
2374             eprintf("no current socket");
2375             return shareval(val_zero);
2376         }
2377 	dc(xsock);
2378     } else if (cstrcmp(args->data + offset, "-all") == 0) {
2379         for (s = hsock; s; s = s->next)
2380 	    if (s->constate < SS_DEAD)
2381 		dc(s);
2382     } else {
2383         if ((s = find_sock(args->data + offset)) && (s->constate < SS_DEAD)) {
2384 	    dc(s);
2385         } else {
2386             eprintf("Not connected to %s", args->data + offset);
2387             return shareval(val_zero);
2388         }
2389     }
2390     return shareval(val_one);
2391 }
2392 
socklinescmp(const void * a,const void * b)2393 static int socklinescmp(const void *a, const void *b) {
2394     return (*(Sock**)a)->world->screen->nnew -
2395 	   (*(Sock**)b)->world->screen->nnew;
2396 }
2397 
sockidlecmp(const void * a,const void * b)2398 static int sockidlecmp(const void *a, const void *b) {
2399     return tvcmp(&(*(Sock**)b)->time[SOCK_RECV],
2400 	         &(*(Sock**)a)->time[SOCK_RECV]);
2401 }
2402 
socknamecmp(const void * a,const void * b)2403 static int socknamecmp(const void *a, const void *b) {
2404     return nullcstrcmp((*(Sock**)a)->world->name, (*(Sock**)b)->world->name);
2405 }
2406 
socktypecmp(const void * a,const void * b)2407 static int socktypecmp(const void *a, const void *b) {
2408     return nullcstrcmp((*(Sock**)a)->world->type, (*(Sock**)b)->world->type);
2409 }
2410 
sockhostcmp(const void * a,const void * b)2411 static int sockhostcmp(const void *a, const void *b) {
2412     return nullcstrcmp((*(Sock**)a)->world->host, (*(Sock**)b)->world->host);
2413 }
2414 
sockportcmp(const void * a,const void * b)2415 static int sockportcmp(const void *a, const void *b) {
2416     return nullcstrcmp((*(Sock**)a)->world->port, (*(Sock**)b)->world->port);
2417 }
2418 
sockcharcmp(const void * a,const void * b)2419 static int sockcharcmp(const void *a, const void *b) {
2420     return nullcstrcmp((*(Sock**)a)->world->character,
2421 		       (*(Sock**)b)->world->character);
2422 }
2423 
2424 /* display list of open sockets and their state. */
handle_listsockets_command(String * args,int offset)2425 struct Value *handle_listsockets_command(String *args, int offset)
2426 {
2427     Sock *sock;
2428     Vector socks = vector_init(32);
2429     char idlebuf[16], linebuf[16], addrbuf[64], state;
2430     const char *ptr;
2431     time_t now;
2432     int t, n, opt, i, nnew, nold;
2433     int error = 0, shortflag = FALSE, mflag = matching, numeric = 0;
2434     Pattern pat_name, pat_type;
2435     int typewidth = 11, namewidth = 15, hostwidth = 26;
2436     int (*cmp)(const void *, const void *) = NULL;
2437 
2438     init_pattern_str(&pat_name, NULL);
2439     init_pattern_str(&pat_type, NULL);
2440 
2441     startopt(CS(args), "m:sT:nS:");
2442     while ((opt = nextopt(&ptr, NULL, NULL, &offset))) {
2443         switch(opt) {
2444         case 'm':
2445             if ((mflag = enum2int(ptr, 0, enum_match, "-m")) < 0)
2446                 goto listsocket_error;
2447             break;
2448         case 's':
2449             shortflag = TRUE;
2450             break;
2451         case 'T':
2452             free_pattern(&pat_type);
2453             error += !init_pattern_str(&pat_type, ptr);
2454             break;
2455 	case 'n':
2456 	    numeric = 1;
2457 	    break;
2458 	case 'S':
2459 	    n = strlen(ptr);
2460 	    if (n == 0 || cstrncmp(ptr, "name", n) == 0)
2461 		cmp = socknamecmp;
2462 	    else if (cstrncmp(ptr, "lines", n) == 0)
2463 		cmp = socklinescmp;
2464 	    else if (cstrncmp(ptr, "idle", n) == 0)
2465 		cmp = sockidlecmp;
2466 	    else if (cstrncmp(ptr, "type", n) == 0)
2467 		cmp = socktypecmp;
2468 	    else if (cstrncmp(ptr, "host", n) == 0)
2469 		cmp = sockhostcmp;
2470 	    else if (cstrncmp(ptr, "port", n) == 0)
2471 		cmp = sockportcmp;
2472 	    else if (cstrncmp(ptr, "character", n) == 0)
2473 		cmp = sockcharcmp;
2474 	    else if (cstrncmp(ptr, "-", n) == 0)
2475 		cmp = NULL;
2476 	    else { eprintf("invalid sort criterion"); error++; }
2477 	    break;
2478         default:
2479             goto listsocket_error;
2480         }
2481     }
2482     if (error) goto listsocket_error;
2483     init_pattern_mflag(&pat_type, mflag, 'T');
2484     Stringstriptrail(args);
2485     if (args->len > offset)
2486         error += !init_pattern(&pat_name, args->data + offset, mflag);
2487     if (error) goto listsocket_error;
2488 
2489     if (!hsock) {
2490         if (!shortflag) eprintf("Not connected to any sockets.");
2491         goto listsocket_error;
2492     }
2493 
2494     /* collect matching socks */
2495     for (sock = hsock; sock; sock = sock->next) {
2496         if (pat_type.str &&
2497             !patmatch(&pat_type, NULL,
2498 		sock->world->type ? sock->world->type : ""))
2499             continue;
2500         if (args->len - offset && !patmatch(&pat_name, NULL, sock->world->name))
2501             continue;
2502 	vector_add(&socks, sock);
2503     }
2504 
2505     if (cmp)
2506 	vector_sort(&socks, cmp);
2507 
2508     if (numeric) {
2509 	namewidth += 3;
2510 	typewidth += 3;
2511 	hostwidth = 20;
2512     }
2513 
2514     now = time(NULL);
2515 
2516     if (!shortflag)
2517         oprintf("    %8s %4s %-*s %-*s %-*s %s",
2518 	    "LINES", "IDLE", typewidth, "TYPE", namewidth, "NAME",
2519 	    hostwidth, "HOST", "PORT");
2520     for (i = 0; i < socks.size; i++) {
2521 	sock = socks.ptrs[i];
2522         nnew = sock->world->screen->nnew;
2523         nold = sock->world->screen->nback - nnew;
2524         if (shortflag) {
2525             oputs(sock->world->name);
2526             continue;
2527         }
2528         if (sock == fsock)
2529             sprintf(linebuf, "%8s", "fg");
2530         else {
2531 	    if (nold) {
2532 		if (nold > 999)
2533 		    sprintf(linebuf, "%2dk", nold / 1000);
2534 		else
2535 		    sprintf(linebuf, "%3d", nold);
2536 		if (nnew > 9999)
2537 		    sprintf(linebuf+3, "+%3dk", nnew / 1000);
2538 		else
2539 		    sprintf(linebuf+3, "+%4d", nnew);
2540 	    } else {
2541 		if (nnew > 99999)
2542 		    sprintf(linebuf, "%7dk", nnew / 1000);
2543 		else
2544 		    sprintf(linebuf, "%8d", nnew);
2545 	    }
2546 	}
2547         t = now - sock->time[SOCK_RECV].tv_sec;
2548         if (t < (60))
2549             sprintf(idlebuf, "%3ds", t);
2550         else if ((t /= 60) < 60)
2551             sprintf(idlebuf, "%3dm", t);
2552         else if ((t /= 60) < 24)
2553             sprintf(idlebuf, "%3dh", t);
2554         else if ((t /= 24) < 1000)
2555             sprintf(idlebuf, "%3dd", t);
2556         else
2557             sprintf(idlebuf, "long");
2558 
2559 	state =
2560 	    sock->constate < SS_CONNECTED ? '?' :
2561             sock->constate >= SS_ZOMBIE ? '!' :
2562 	    sock->constate == SS_OPEN ? 'O' :
2563 	    sock->constate == SS_CONNECTED && sock->fsastate == TN_SB ? 'S' :
2564 #if HAVE_SSL
2565 	    sock->constate == SS_CONNECTED && sock->ssl ? 'X' :
2566 #endif
2567 	    sock->constate == SS_CONNECTED ? 'C' :
2568 	    '#' /* shouldn't happen */;
2569 	if (sock->flags & SOCKCOMPRESS)
2570 	    state = lcase(state);
2571 	if (!numeric && sock->addr)
2572 	    sprintf(addrbuf, "%-*.*s %.6s",
2573 		hostwidth, hostwidth, sock->host, sock->port);
2574         oprintf("%c%c%c"
2575 	    " %s %s %-*.*s %-*.*s %s",
2576             (sock == xsock ? '*' : ' '),
2577 	    state,
2578 	    (sock->flags & SOCKPROXY ? 'P' : ' '),
2579             linebuf, idlebuf,
2580             typewidth, typewidth, sock->world->type,
2581 	    namewidth, namewidth, sock->world->name,
2582 	    !sock->addr ? "" : numeric ? printai(sock->addr, "%-20.20s %d") :
2583 		addrbuf);
2584     }
2585 
2586 listsocket_error:
2587     free_pattern(&pat_name);
2588     free_pattern(&pat_type);
2589 
2590     return newint(socks.size);
2591 }
2592 
handle_send_function(conString * string,const char * world,const char * flags)2593 int handle_send_function(conString *string, const char *world,
2594     const char *flags)
2595 {
2596     const char *p;
2597     int result = 0, eol_flag = 1, hook_flag = 0;
2598     Sock *old_xsock = xsock;
2599 
2600     for (p = flags; *p; p++) {
2601 	switch (*p) {
2602 	case 'o': /* for backward compatability */
2603 	    break;
2604 	case '1': case 'n': /* for backward compatability */
2605 	    eol_flag = 1; break;
2606 	case 'u': /* fall through */
2607 	case '0': case 'f': /* for backward compatability */
2608 	    eol_flag = 0; break;
2609 	case 'h':
2610 	    hook_flag = 1; break;
2611 	default:
2612 	    eprintf("invalid flag %c", *p);
2613 	    return 0;
2614 	}
2615     }
2616 
2617     xsock = (!world || !*world) ? xsock : find_sock(world);
2618     if (!hook_flag || !do_hook(H_SEND, NULL, "%S", string))
2619 	result = send_line(string->data, string->len, eol_flag);
2620     xsock = old_xsock;
2621     return result;
2622 }
2623 
2624 #if ENABLE_ATCP
handle_atcp_function(conString * string,const char * world)2625 int handle_atcp_function(conString *string, const char *world)
2626 {
2627     Sock *old_xsock = xsock;
2628 
2629     xsock = (!world || !*world) ? xsock : find_sock(world);
2630         Sprintf(telbuf, "%c%c%c%s%c%c", TN_IAC, TN_SB, TN_ATCP, string->data, TN_IAC, TN_SE);
2631         telnet_send(telbuf);
2632     xsock = old_xsock;
2633         return 1;
2634 }
2635 #endif
2636 
2637 #if ENABLE_GMCP
handle_gmcp_function(conString * string,const char * world)2638 int handle_gmcp_function(conString *string, const char *world)
2639 {
2640     Sock *old_xsock = xsock;
2641 
2642     xsock = (!world || !*world) ? xsock : find_sock(world);
2643         Sprintf(telbuf, "%c%c%c%s%c%c", TN_IAC, TN_SB, TN_GMCP, string->data, TN_IAC, TN_SE);
2644         telnet_send(telbuf);
2645     xsock = old_xsock;
2646         return 1;
2647 }
2648 #endif
2649 
2650 #if ENABLE_OPTION102
handle_option102_function(conString * string,const char * world)2651 int handle_option102_function(conString *string, const char *world)
2652 {
2653     Sock *old_xsock = xsock;
2654 
2655     xsock = (!world || !*world) ? xsock : find_sock(world);
2656         Sprintf(telbuf, "%c%c%c%s%c%c", TN_IAC, TN_SB, TN_102, string->data, TN_IAC, TN_SE);
2657         telnet_send(telbuf);
2658     xsock = old_xsock;
2659         return 1;
2660 }
2661 #endif
2662 
2663 /* Code for the undocumented fake_recv script function. */
handle_fake_recv_function(conString * string,const char * world,const char * flags)2664 int handle_fake_recv_function(conString *string, const char *world,
2665     const char *flags)
2666 {
2667     Sock *sock;
2668     int raw = 0;
2669     const char *p;
2670 
2671     for (p = flags; *p; p++) {
2672 	switch (*p) {
2673 	case 'r': raw = 1; break;
2674 	default:
2675 	    eprintf("invalid flag %c", *p);
2676 	    return 0;
2677 	}
2678     }
2679 
2680     sock = (!world || !*world) ? xsock : find_sock(world);
2681     if (!sock ||
2682 	sock->constate <= SS_CONNECTING || sock->constate >= SS_ZOMBIE)
2683     {
2684         eprintf("no open world %s", world ? world : "");
2685 	return 0;
2686     }
2687     if (raw)
2688     {
2689 	handle_socket_input(string->data, string->len, NULL);
2690     }
2691     else {
2692 	queue_socket_line(sock, string, string->len, 0);
2693 	flushxsock();
2694     }
2695     return 1;
2696 }
2697 
2698 
2699 /* transmit bytes to current socket */
transmit(const char * str,unsigned int numtowrite)2700 static int transmit(const char *str, unsigned int numtowrite)
2701 {
2702     int numwritten, err;
2703 
2704     if (!xsock || xsock->constate != SS_CONNECTED)
2705         return 0;
2706     while (numtowrite) {
2707 #if HAVE_SSL
2708 	if (xsock->ssl) {
2709 	    numwritten = SSL_write(xsock->ssl, str, numtowrite);
2710 	    if (numwritten <= 0) {
2711 		zombiesock(xsock); /* before hook, so sock state is correct */
2712 		ssl_io_err(xsock, numwritten, H_DISCONNECT);
2713 		return 0;
2714 	    }
2715 	} else
2716 #endif /* HAVE_SSL */
2717 	{
2718 	    numwritten = send(xsock->fd, str, numtowrite, 0);
2719 	    if (numwritten < 0) {
2720 		err = errno;
2721 		/* Socket is blocking; EAGAIN and EWOULDBLOCK are impossible. */
2722 		if (err == EINTR) {
2723 		    return 0;
2724 		} else if (err == EHOSTUNREACH || err == ENETUNREACH) {
2725 		    /* XXX there should be an UNREACHABLE hook here */
2726 		    eprintf("%s: send: %s", xsock->world->name, strerror(err));
2727 		    return 0;
2728 		} else {
2729 		    flushxsock();
2730 		    zombiesock(xsock); /* before hook, so state is correct */
2731 		    DISCON(xsock->world->name, "send", strerror(err));
2732 		    return 0;
2733 		}
2734 	    }
2735 	}
2736         numtowrite -= numwritten;
2737         str += numwritten;
2738         gettime(&xsock->time[SOCK_SEND]);
2739     }
2740     return 1;
2741 }
2742 
2743 /* send_line
2744  * Send a line to the server on the current socket.  If there is a prompt
2745  * associated with the current socket, clear it.
2746  * RFCs 854 and 1123 technically forbid sending 8-bit data in non-BINARY mode;
2747  * but if the user types it, we send it regardless of BINARY mode, and trust
2748  * the user to know what he's doing.  Some servers accept it, some strip the
2749  * high bit, some ignore the characters.
2750  */
send_line(const char * src,unsigned int len,int eol_flag)2751 int send_line(const char *src, unsigned int len, int eol_flag)
2752 {
2753     int needed;
2754     int i = 0, j = 0;
2755     static char *buffer1 = NULL;
2756     static int bufferlen = 0;
2757     static char *buffer2 = NULL;
2758 
2759 #if WIDECHAR
2760     /* utf16buf could take less space if it was a union with buffer2 */
2761     /* For now, I just want it to work. :) */
2762     static UChar *utf16buf = NULL;
2763     const UChar *utf16_source;
2764     char *target;
2765     UErrorCode err;
2766     UBool ubool_true = TRUE;
2767 #endif
2768 
2769     if (!xsock ||
2770 	(xsock->constate != SS_CONNECTED && !(xsock->flags & SOCKECHO)))
2771     {
2772         eprintf("Not connected.");
2773         return 0;
2774     }
2775 
2776     if (xsock && xsock->prompt) {
2777         /* Not the same as unprompt(): we keep attrs, and delete buffer. */
2778 	if (!(xsock->flags & SOCKPROMPT)) {
2779 	    /* Prompt was implicit, so there's still a copy in xsock->buffer */
2780 	    Stringtrunc(xsock->buffer, 0);
2781 	} else {
2782 	    /* Prompt was explicit, so anything in xsock->buffer is an
2783 	     * unrelated partial line that we must keep. */
2784 	}
2785         conStringfree(xsock->prompt);
2786         xsock->prompt = NULL;
2787         xsock->prepromptattrs = 0;
2788         if (xsock == fsock) update_prompt(xsock->prompt, 1);
2789     }
2790 
2791     if (secho) {
2792 	String *str = Stringnew(NULL, 0, 0);
2793 	Sprintf(str, "%S%.*s%A", sprefix, len, src, getattrvar(VAR_secho_attr));
2794 	world_output(xsock->world, CS(str));
2795     }
2796 
2797     /* Steps:
2798      * 1) Copy src to buffer1, add newline endings
2799      * 2) Convert string to UTF-16 -> buffer2
2800      * 3) Convert string to xsock->charset -> buffer1
2801      * 4) Double all Telnet IAC -> buffer2
2802      * 5) Transmit buffer2.
2803      */
2804 
2805     needed = (len + 3) * 8;
2806     if (bufferlen < needed) {
2807         bufferlen = needed;
2808         buffer1 = XREALLOC(buffer1, bufferlen);
2809         buffer2 = XREALLOC(buffer2, bufferlen);
2810 #if WIDECHAR
2811         /* 'needed' calculated as 8-bit wide, not 16-bit */
2812         utf16buf = XREALLOC(utf16buf, bufferlen / 2);
2813 #endif
2814     }
2815 
2816     memcpy(buffer1, src, len);
2817 
2818     if (eol_flag) {
2819         /* In telnet NVT mode, append CR LF; in telnet BINARY mode,
2820          * append LF, CR, or CR LF, according to variable.
2821          */
2822         if (!TELOPT(xsock, us, TN_BINARY) || binary_eol != EOL_LF)
2823             buffer1[len++] = '\r';
2824         if (!TELOPT(xsock, us, TN_BINARY) || binary_eol != EOL_CR)
2825             buffer1[len++] = '\n';
2826     }
2827 
2828 #if WIDECHAR
2829     /* Buf1 -> Buf2  [UTF8  -> UTF16] */
2830     /* Buf2 -> Buf1  [UTF16 -> XCHAR] */
2831     err = U_ZERO_ERROR;
2832     target = buffer1;
2833     utf16_source = utf16buf;
2834     /* First attempt at fixing. Probably better to make this one stick
2835      * around longer but enh. */
2836     UConverter *utf8_conv = ucnv_open("UTF8", &err);
2837     ucnv_setToUCallBack(utf8_conv, UCNV_TO_U_CALLBACK_ESCAPE,
2838                         UCNV_ESCAPE_XML_HEX, NULL, NULL, &err);
2839     j = ucnv_toUChars(utf8_conv, utf16buf, bufferlen / 2, buffer1, len, &err);
2840     ucnv_close(utf8_conv);
2841     /* dest, dest_len, written_units, src, src_len, errors */
2842     /* u_strFromUTF8(utf16buf, bufferlen / 2, &j, buffer1, len, &err); */
2843     /* 'incomingfsm' has an outgoing state machine, as well. Used here. */
2844     ucnv_resetFromUnicode(xsock->incomingfsm);
2845     ucnv_fromUnicode(xsock->incomingfsm,  /* Converter */
2846             &target, buffer1 + bufferlen, /* target, limit_ptr */
2847             &utf16_source, utf16buf + j,  /* source, limit_ptr */
2848             NULL, ubool_true, &err);      /* offsets, flush, errors */
2849     len = target - buffer1; /* 'target' is moved to end during conversion */
2850 
2851     if (U_FAILURE(err))
2852     {
2853         eprintf("Broken characters found. Line not sent.");
2854         return 0;
2855         /* core("outbound_decode U_FAILURE", __FILE__, __LINE__, 0); */
2856     }
2857 #endif
2858 
2859     /* Buf1 -> Buf2  [Telnet escape]   */
2860     i = 0; j = 0;
2861     while (j < len) {
2862         if (xsock->flags & SOCKTELNET && buffer1[j] == TN_IAC)
2863             buffer2[i++] = TN_IAC;    /* double IAC */
2864         buffer2[i] = unmapchar(buffer1[j]);
2865         i++; j++;
2866     }
2867 
2868     if (xsock->flags & SOCKECHO)
2869         handle_socket_input(buffer2, i, "UTF-8");
2870     if (xsock->constate == SS_CONNECTED)
2871         return transmit(buffer2, i);
2872     return 1;
2873 }
2874 
handle_socket_lines(void)2875 static void handle_socket_lines(void)
2876 {
2877     static int depth = 0;
2878     conString *line;
2879     int is_prompt;
2880 
2881     if (depth) return;	/* don't recurse */
2882     if (!(line = dequeue(&xsock->queue)))
2883 	return;
2884     depth++;
2885     do {
2886 	if (!xsock->queue.list.head) /* just dequeued the last line */
2887 	    socks_with_lines--;
2888 
2889 	if (line->attrs & (F_TFPROMPT)) {
2890 	    incoming_text = (String *) line;
2891 	    handle_prompt(incoming_text, 0, TRUE);
2892 	    continue;
2893 	}
2894 
2895 	incoming_text = decode_ansi(line->data, xsock->attrs, emulation,
2896 	    &xsock->attrs);
2897 	incoming_text->time = line->time;
2898 	is_prompt = line->attrs & F_SERVPROMPT;
2899 	conStringfree(line);
2900 	incoming_text->links++;
2901 
2902 	if (is_prompt) {
2903 	    if (do_hook(H_PROMPT, NULL, "%S", incoming_text)) {
2904 		Stringfree(incoming_text);
2905 	    } else {
2906 		handle_prompt(incoming_text, 0, TRUE);
2907 	    }
2908 
2909 	} else {
2910 	    if (borg || hilite || gag) {
2911 		if (find_and_run_matches(NULL, -1, &incoming_text, xworld(),
2912 		    TRUE, 0))
2913 		{
2914 		    if (xsock != fsock)
2915 			do_hook(H_BGTRIG, "%% Trigger in world %s", "%s %S",
2916 			    xsock->world->name, incoming_text);
2917 		}
2918 	    }
2919 
2920 	    if (is_bamf(incoming_text->data) || is_quiet(incoming_text->data) ||
2921 		is_watchdog(xsock->world->history, incoming_text) ||
2922 		is_watchname(xsock->world->history, incoming_text))
2923 	    {
2924 		incoming_text->attrs |= F_GAG;
2925 	    }
2926 
2927 	    world_output(xsock->world, CS(incoming_text));
2928 	    Stringfree(incoming_text);
2929 	}
2930     } while ((line = dequeue(&xsock->queue)));
2931     depth--;
2932 
2933     /* We just emptied the queue; there may be a partial line pending */
2934     test_prompt();
2935 }
2936 
2937 /* log, record, and display line as if it came from sock */
world_output(World * world,conString * line)2938 void world_output(World *world, conString *line)
2939 {
2940     Sock *saved_xsock = xsock;
2941     xsock = world ? world->sock : NULL;
2942     line->links++;
2943     recordline(world->history, line);
2944     record_global(line);
2945     if (world->sock && (world->sock->constate < SS_DEAD) &&
2946 	!(gag && (line->attrs & F_GAG)))
2947     {
2948         if (world->sock == fsock) {
2949             screenout(line);
2950         } else {
2951 	    static int preactivity_depth = 0; /* avoid recursion */
2952 	    /* line was already tested for gag, so it WILL print */
2953 	    if (!preactivity_depth && !world->screen->active) {
2954 		preactivity_depth++;
2955                 do_hook(H_PREACTIVITY, NULL, "%s", world->name);
2956 		preactivity_depth--;
2957 	    }
2958             enscreen(world->screen, line); /* ignores preactivity_depth */
2959             if (!preactivity_depth) {
2960 		if (!world->screen->active && !(line->attrs & F_NOACTIVITY)) {
2961 		    world->screen->active = 1;
2962 		    ++active_count;
2963 		    update_status_field(NULL, STAT_ACTIVE);
2964 		    do_hook(H_ACTIVITY, "%% Activity in world %s", "%s",
2965 			world->name);
2966 		}
2967 		do_hook(H_BGTEXT, NULL, "%s", world->name);
2968             }
2969         }
2970     }
2971     conStringfree(line);
2972     xsock = saved_xsock;
2973 }
2974 
2975 /* get the prompt for the fg sock */
fgprompt(void)2976 conString *fgprompt(void)
2977 {
2978     return (fsock) ? fsock->prompt : NULL;
2979 }
2980 
tog_lp(Var * var)2981 int tog_lp(Var *var)
2982 {
2983     if (!fsock) {
2984         /* do nothing */
2985     } else if (lpflag) {
2986         if (!fsock->queue.list.head && fsock->buffer->len) {
2987             fsock->prompt = CS(decode_ansi(fsock->buffer->data, fsock->attrs,
2988                 emulation, &fsock->attrs));
2989             fsock->prompt->links++;
2990             set_refresh_pending(REF_PHYSICAL);
2991         }
2992     } else {
2993         if (fsock->prompt && !(fsock->flags & SOCKPROMPT)) {
2994             unprompt(fsock, 1);
2995             set_refresh_pending(REF_PHYSICAL);
2996         }
2997     }
2998     return 1;
2999 }
3000 
handle_prompt_func(conString * str)3001 int handle_prompt_func(conString *str)
3002 {
3003     if (xsock)
3004 	queue_socket_line(xsock, str, str->len, F_TFPROMPT);
3005     return !!xsock;
3006 }
3007 
handle_prompt(String * str,int offset,int confirmed)3008 static void handle_prompt(String *str, int offset, int confirmed)
3009 {
3010     runall(1, xsock->world);	/* run prompted processes */
3011     if (xsock->prompt) {
3012         unprompt(xsock, 0);
3013     }
3014     assert(str->links == 1);
3015     xsock->prompt = CS(str);
3016     /* Old versions did trigger checking here.  Removing it breaks
3017      * compatibility, but I doubt many users will care.  Leaving
3018      * it in would not be right for /prompt.
3019      */
3020     if (xsock == fsock) update_prompt(xsock->prompt, 1);
3021     if (confirmed) xsock->flags |= SOCKPROMPT;
3022     else xsock->flags &= ~SOCKPROMPT;
3023     xsock->numquiet = 0;
3024 }
3025 
handle_implicit_prompt(void)3026 static void handle_implicit_prompt(void)
3027 {
3028     String *new;
3029 
3030     xsock->prompt_timeout = tvzero;
3031     xsock->prepromptattrs = xsock->attrs; /* save attrs for unprompt() */
3032 
3033     new = decode_ansi(xsock->buffer->data, xsock->attrs, emulation,
3034 	&xsock->attrs);
3035     new->links++;
3036 
3037     handle_prompt(new, 0, FALSE);
3038 }
3039 
3040 /* undo the effects of a false prompt */
unprompt(Sock * sock,int update)3041 static void unprompt(Sock *sock, int update)
3042 {
3043     if (!sock || !sock->prompt || !(sock->flags & SOCKPROMPT)) return;
3044     sock->attrs = sock->prepromptattrs;  /* restore original attrs */
3045     conStringfree(sock->prompt);
3046     sock->prompt = NULL;
3047     sock->prepromptattrs = 0;
3048     if (update) update_prompt(sock->prompt, 1);
3049 }
3050 
schedule_prompt(Sock * sock)3051 static void schedule_prompt(Sock *sock)
3052 {
3053     if (prompt_timeout.tv_sec == 0 ||
3054 	tvcmp(&sock->prompt_timeout, &prompt_timeout) < 0)
3055     {
3056 	prompt_timeout = sock->prompt_timeout;
3057     }
3058 }
3059 
test_prompt(void)3060 static void test_prompt(void)
3061 {
3062     if (lpflag && !xsock->queue.list.head && xsock->buffer->len) {
3063 	if (do_hook(H_PROMPT, NULL, "%S", xsock->buffer)) {
3064 	    /* The hook took care of the unterminated line. */
3065 	    Stringtrunc(xsock->buffer, 0);
3066 	} else if (lpflag) {
3067 	    /* Wait for prompt_wait before treating unterm'd line as prompt. */
3068 	    struct timeval now;
3069 	    gettime(&now);
3070 	    tvadd(&xsock->prompt_timeout, &now, &prompt_wait);
3071 	    schedule_prompt(xsock);
3072 	}
3073     }
3074 }
3075 
telnet_subnegotiation(void)3076 static void telnet_subnegotiation(void)
3077 {
3078     unsigned int i;
3079     char *p, *end;
3080     char temp_buff[255]; /* Same length as whole subnegotiation line. */
3081     char *temp_ptr;
3082     int ttype;
3083     char charset_sep = '\0';
3084 #if WIDECHAR
3085     UConverter* newconverter = NULL;
3086     UErrorCode newconvertererr;
3087 #endif
3088 
3089     static conString enum_ttype[] = {
3090         STRING_LITERAL("TINYFUGUE"),
3091         STRING_LITERAL("ANSI-ATTR"),
3092         STRING_LITERAL("ANSI"), /* a lie, but probably has the desired effect */
3093         STRING_LITERAL("UNKNOWN"),
3094         STRING_NULL };
3095 
3096     telnet_debug("recv", xsock->subbuffer->data, xsock->subbuffer->len);
3097     Stringtrunc(xsock->subbuffer, xsock->subbuffer->len - 2);
3098     p = xsock->subbuffer->data + 2;
3099     end = p + xsock->subbuffer->len;
3100     switch (*p) {
3101     case TN_TTYPE:
3102 	if (!TELOPT(xsock, us, *p)) {
3103 	    no_reply("option was not agreed on");
3104 	    break;
3105 	}
3106         if (*++p != '\01' || xsock->subbuffer->len != 4) {
3107 	    no_reply("invalid syntax");
3108 	    break;
3109 	}
3110         Sprintf(telbuf, "%c%c%c%c", TN_IAC, TN_SB, TN_TTYPE, '\0');
3111         ttype = ++xsock->ttype;
3112         if (!enum_ttype[ttype].data) { ttype--; xsock->ttype = -1; }
3113         SStringcat(telbuf, &enum_ttype[ttype]);
3114         Sappendf(telbuf, "%c%c", TN_IAC, TN_SE);
3115         telnet_send(telbuf);
3116         break;
3117     case TN_COMPRESS:
3118     case TN_COMPRESS2:
3119 	if (!TELOPT(xsock, them, *p)) {
3120 	    no_reply("option was not agreed on");
3121 	    break;
3122 	}
3123 	xsock->flags |= SOCKCOMPRESS;
3124 	break;
3125 #if WIDECHAR
3126     case TN_CHARSET:
3127         if (!TELOPT(xsock, them, *p)) {
3128             no_reply("option was not agreed upon");
3129             break;
3130         }
3131         if (*++p == '\01') { /* REQUEST <sep> <character set>... */
3132            charset_sep = *++p;
3133            while (p != end) {
3134               temp_ptr = ++p;
3135               while (p != end && *p != charset_sep) {
3136                   temp_buff[p - temp_ptr] = (*p & ~0x80);
3137                   ++p;
3138               }
3139               temp_buff[p - temp_ptr] = '\0';
3140               newconvertererr = U_ZERO_ERROR;
3141               newconverter = ucnv_open(temp_buff, &newconvertererr);
3142           /* TODO: Check U_MEMORY_ALLOCATION_ERROR and U_FILE_ACCESS_ERROR */
3143               if (newconverter != NULL) {
3144                   p = end; /* Prefer the first valid charset! */
3145               }
3146            }
3147            if (newconverter != NULL) {
3148               Sprintf(telbuf, "%c%c%c%c%s%c%c", TN_IAC, TN_SB, TN_CHARSET, '\02', temp_buff, TN_IAC, TN_SE);
3149               /* TODO: Don't reset if we're already using this charset. */
3150               /* XXX: This breaks if we were scanning simbuffer. Dangit. */
3151               inbound_decode_str(xsock->buffer, xsock->incomingposttelnet,
3152                   xsock->incomingfsm, 1); /* 1; nothing else to convert */
3153               handle_socket_input_queue_lines(xsock);
3154               ucnv_close(xsock->incomingfsm);
3155               xsock->incomingfsm = newconverter;
3156            } else {
3157               Sprintf(telbuf, "%c%c%c%c%c%c", TN_IAC, TN_SB, TN_CHARSET, '\03', TN_IAC, TN_SE);
3158            }
3159         } else {
3160             no_reply("option not implemented");
3161             break;
3162         }
3163         telnet_send(telbuf);
3164         break;
3165 #endif
3166 #if ENABLE_ATCP
3167     case TN_ATCP:
3168 	    do_hook(H_ATCP, NULL, "%s", xsock->subbuffer->data + 3);
3169 	    break;
3170 #endif
3171 #if ENABLE_GMCP
3172     case TN_GMCP:
3173 	    do_hook(H_GMCP, NULL, "%s", xsock->subbuffer->data + 3);
3174 	    break;
3175 #endif
3176 #if ENABLE_OPTION102
3177     case TN_102:
3178 	    do_hook(H_OPTION102, NULL, "%s", xsock->subbuffer->data + 3);
3179 	    break;
3180 #endif
3181     default:
3182 	no_reply("unknown option");
3183         break;
3184     }
3185     Stringtrunc(xsock->subbuffer, 0);
3186 }
3187 
f_telnet_recv(int cmd,int opt)3188 static void f_telnet_recv(int cmd, int opt)
3189 {
3190     if (telopt) {
3191         char buf[4];
3192         sprintf(buf, "%c%c%c", TN_IAC, cmd, opt);
3193         telnet_debug("recv", buf,
3194             (cmd==(UCHAR)TN_DO || cmd==(UCHAR)TN_DONT ||
3195              cmd==(UCHAR)TN_WILL || cmd==(UCHAR)TN_WONT) ?
3196              3 : 2);
3197     }
3198 }
3199 
3200 #if HAVE_MCCP
new_zstream(void)3201 static z_stream *new_zstream(void)
3202 {
3203     z_stream *zstream;
3204     if (!(zstream = MALLOC(sizeof(z_stream))))
3205 	return NULL;
3206     zstream->zalloc = Z_NULL;
3207     zstream->zfree = Z_NULL;
3208     zstream->opaque = Z_NULL;
3209     if (inflateInit(zstream) == Z_OK)
3210 	return zstream;
3211     if (zstream->msg)
3212 	eprintf("unable to start compressed stream: %s", zstream->msg);
3213     FREE(zstream);
3214     return NULL;
3215 }
3216 #endif /* HAVE_MCCP */
3217 
3218 #if WIDECHAR
inbound_decode_str(String * output,String * input,UConverter * conv,const char cflush)3219 static int inbound_decode_str(String *output, String *input, UConverter *conv, const char cflush)
3220 {
3221     int shiftby = 0;
3222     if (input->data < input->data + input->len) {
3223         shiftby = inbound_decode(output, input->data, input->data + input->len, conv, cflush);
3224     }
3225     if (shiftby > 0) {
3226         if (cflush == 0) {
3227             Stringshift(input, shiftby);
3228         } else {
3229             Stringtrunc(input, 0);
3230         }
3231     }
3232     return shiftby;
3233 }
3234 /* Take input of a particular encoding and Stringcat it into 'output'.
3235  * Flush shold be FALSE(0) unless the socket is being shut down.
3236  * Returns number of bytes the input pointer should increment.
3237  * Only modifies 'output' and 'conv' arguments.
3238  */
inbound_decode(String * output,const char * input,const char * iendptr,UConverter * conv,const char cflush)3239 static int inbound_decode(String *output, const char *input, const char *iendptr, UConverter *conv, const char cflush)
3240 {
3241     /* This definitely, definitely needs optimizations for
3242           * ISO-8859-1 -> UTF-8, and UTF-8 -> UTF-8. */
3243     const char *iptr = input;
3244 
3245     UChar outbufferUTF16[BUFFSIZE*4];
3246     UChar *optr = outbufferUTF16;
3247     const UChar *oendptr = outbufferUTF16 + BUFFSIZE*4;
3248     UErrorCode err16 = U_ZERO_ERROR;
3249 
3250     char outbufferUTF8[BUFFSIZE*8];
3251     UErrorCode err8 = U_ZERO_ERROR;
3252     int32_t utf8written = 0;
3253 
3254     UBool flush = cflush ? TRUE : FALSE;
3255 
3256     /* xcharset -> UTF-16 -> UTF-8 */
3257     ucnv_toUnicode(conv, &optr, oendptr, &iptr, iendptr, NULL, flush, &err16);
3258 /*
3259 void ucnv_toUnicode 	( 	UConverter *  	converter,
3260 		UChar **  	target,
3261 		const UChar *  	targetLimit,
3262 		const char **  	source,
3263 		const char *  	sourceLimit,
3264 		int32_t *  	offsets,
3265 		UBool  	flush,
3266 		UErrorCode *  	err
3267 	)
3268 */
3269     u_strToUTF8(outbufferUTF8, BUFFSIZE*8, &utf8written, outbufferUTF16, (int32_t)(optr - outbufferUTF16), &err8);
3270 /*
3271 char* u_strToUTF8 	( 	char *  	dest,
3272 		int32_t  	destCapacity,
3273 		int32_t *  	pDestLength,
3274 		const UChar *  	src,
3275 		int32_t  	srcLength,
3276 		UErrorCode *  	pErrorCode
3277 	)
3278 */
3279     Stringfncat(output, outbufferUTF8, utf8written);
3280     if (U_FAILURE(err16) || U_FAILURE(err8))
3281         core("inbound_decode U_FAILURE", __FILE__, __LINE__, 0);
3282     return (iptr - input); /* return number of input bytes consumed */
3283 
3284 }
3285 #endif
3286 /* handle input from current socket
3287  * simbuffer and simlen are 'simulation', used when recursing (from MCCP)
3288  * or when we're simulating input, such as from local echo from send_line.
3289  * If 'encoding' is NULL then this writes to the partial socket buffers,
3290  * otherwise initializes and uses a new converter.
3291  */
handle_socket_input(const char * simbuffer,int simlen,const char * encoding)3292 static int handle_socket_input(const char *simbuffer, int simlen, const char *encoding)
3293 {
3294     char rawchar, localchar, inbuffer[BUFFSIZE];
3295     const char *incoming, *place;
3296 #if HAVE_MCCP
3297     char mccpbuffer[BUFFSIZE];
3298 #endif
3299     fd_set readfds;
3300     int count, n, received = 0;
3301     struct timeval timeout;
3302 #if WIDECHAR
3303     String *incomingposttelnet;
3304     UConverter *incomingFSM = NULL;
3305     UErrorCode incomingERR;
3306     int shiftby;
3307 #endif
3308 
3309     if (xsock->constate <= SS_CONNECTING || xsock->constate >= SS_ZOMBIE)
3310 	return 0;
3311 
3312    /* We assumed last text was a prompt, but now we have more text, so
3313     * we now assume that they are both part of the same long line.  (If
3314     * we're wrong, the previous prompt appears as output.  But if we did
3315     * the opposite, a real begining of a line would never appear in the
3316     * output window; that would be a worse mistake.)
3317     * Note that a terminated (EOR or GOAHEAD) prompt will NOT be cleared
3318     * when new text arrives (it will only be cleared when there is a new
3319     * prompt).
3320     */
3321     if (xsock->prompt && !(xsock->flags & SOCKPROMPT)) {
3322         unprompt(xsock, xsock==fsock);
3323     }
3324     xsock->prompt_timeout = tvzero;
3325 
3326 #if WIDECHAR
3327     if (encoding == NULL) {
3328 	incomingposttelnet = xsock->incomingposttelnet;
3329 	incomingFSM = xsock->incomingfsm;
3330     } else {
3331         /* Using simlen because we assume we'll have UTF-8 anyway */
3332 	incomingposttelnet = Stringnew(NULL, simlen, 0);
3333 	incomingFSM = ucnv_open(encoding, &incomingERR);
3334 	if (incomingERR == U_MEMORY_ALLOCATION_ERROR || incomingERR == U_FILE_ACCESS_ERROR)
3335             core("TN_CHARSET: Could not create UConverter.", __FILE__, __LINE__, 0);
3336     }
3337 #endif
3338 
3339     do {  /* while there are more data to be processed */
3340 	if (simbuffer) {
3341 	    incoming = simbuffer;
3342 	    count = simlen;
3343 	} else {
3344 #if HAVE_MCCP
3345 	    if (xsock->zstream && xsock->zstream->avail_in) {
3346 		count = 0;  /* no reading */
3347 	    } else
3348 #endif
3349 #if HAVE_SSL
3350 	    if (xsock->ssl) {
3351 		count = SSL_read(xsock->ssl, inbuffer, sizeof(inbuffer));
3352 		if (count == 0 &&
3353 		    SSL_get_error(xsock->ssl, 0) == SSL_ERROR_SYSCALL &&
3354 		    ERR_peek_error() == 0)
3355 		{
3356 		    /* Treat a count of 0 with no errors as a normal EOF */
3357 		    goto eof;
3358 		} else if (count <= 0) {
3359 		    /* Treat an error or a bad EOF as an error */
3360 		    zombiesock(xsock); /* before hook, so state is correct */
3361 		    ssl_io_err(xsock, count, H_DISCONNECT);
3362 		    return received;
3363 		}
3364 	    } else
3365 #endif
3366 	    {
3367 		/* We could loop while (count < 0 && errno == EINTR), but if we
3368 		 * got here because of a mistake in the active fdset and there
3369 		 * is really nothing to read, the loop would be unbreakable. */
3370 		count = recv(xsock->fd, inbuffer, sizeof(inbuffer), 0);
3371 		eof:
3372 		if (count <= 0) {
3373 		    int err = errno;
3374 		    constate_t state = xsock->constate;
3375 		    if (count < 0 && errno == EINTR)
3376 			return 0;
3377 		    /* Socket is blocking; EAGAIN and EWOULDBLOCK impossible. */
3378 #if WIDECHAR
3379 		    inbound_decode_str(xsock->buffer, incomingposttelnet,
3380                         incomingFSM, 1);
3381 #endif
3382 		    if (xsock->buffer->len) { /* Destroy the buffers */
3383 			handle_socket_input_queue_lines(xsock);
3384 			queue_socket_line(xsock, CS(xsock->buffer), xsock->buffer->len, 0);
3385 			Stringtrunc(xsock->buffer, 0);
3386 		    }
3387 		    flushxsock();
3388 		    /* On some systems, a socket that failed nonblocking connect
3389 		     * selects readable instead of writable.  If SS_CONNECTING,
3390 		     * that's what happened, so we do CONFAIL not DISCONNECT.
3391 		     */
3392 		    zombiesock(xsock); /* before hook, so constate is correct */
3393 		    if (state == SS_CONNECTING)
3394 			CONFAIL(xsock, "recv", strerror(err));
3395 		    else do_hook(H_DISCONNECT, (count < 0) ?
3396 			"%% Connection to %s closed: %s: %s" :
3397 			"%% Connection to %s closed by foreign host.",
3398 			(count < 0) ? "%s %s %s" : "%s",
3399 			xsock->world->name, "recv", strerror(err));
3400 		    return received;
3401 		}
3402 	    }
3403 #if HAVE_MCCP
3404 	    if (xsock->zstream) {
3405 		int zret;
3406 		if (count) {
3407 		    xsock->zstream->next_in = (Bytef*)inbuffer;
3408 		    xsock->zstream->avail_in = count;
3409 		}
3410 		xsock->zstream->next_out = (Bytef*)(incoming = mccpbuffer);
3411 		xsock->zstream->avail_out = sizeof(mccpbuffer);
3412 		zret = inflate(xsock->zstream, Z_PARTIAL_FLUSH);
3413 		switch (zret) {
3414 		case Z_OK:
3415 		    count = (char*)xsock->zstream->next_out - mccpbuffer;
3416 		    break;
3417 		case Z_STREAM_END:
3418 		    /* handle stuff inflated before stream end */
3419 		    /* NOTE: This could be partway into parsing a character!? */
3420 		    count = (char*)xsock->zstream->next_out - mccpbuffer;
3421 		    received += handle_socket_input(mccpbuffer, count, NULL);
3422 		    /* prepare to handle noncompressed stuff after stream end */
3423 		    incoming = (char*)xsock->zstream->next_in;
3424 		    count = xsock->zstream->avail_in;
3425 		    /* clean up zstream */
3426 		    inflateEnd(xsock->zstream);
3427 		    FREE(xsock->zstream);
3428 		    xsock->zstream = NULL;
3429 		    xsock->flags &= ~SOCKCOMPRESS;
3430 		    break;
3431 		default:
3432 		    flushxsock();
3433 		    zombiesock(xsock); /* before hook, so constate is correct */
3434 		    DISCON(xsock->world->name, "inflate",
3435 			xsock->zstream->msg ? xsock->zstream->msg : "unknown");
3436 		    return received;
3437 		}
3438 	    } else
3439 #endif
3440 		incoming = inbuffer;
3441 	}
3442 
3443 	/* At this point, buffer is the latest chunk of data received */
3444 	/* Unpeel the Telnet commands from the data stream */
3445         for (place = incoming; place - incoming < count; place++) {
3446             rawchar = *place;
3447             localchar = localize(rawchar);
3448 
3449             /* Telnet processing
3450              * If we're not sure yet whether server speaks telnet protocol,
3451              * we still accept it, but if an invalid telnet command arrives,
3452              * we leave it alone and disable telnet processing.
3453              */
3454             if (xsock->fsastate == TN_IAC &&
3455                 xsock->flags & (SOCKTELNET | SOCKMAYTELNET))
3456             {
3457                 int valid = 0;
3458                 switch (xsock->fsastate = rawchar) {
3459                 case TN_GA: case TN_EOR:
3460                     /* This is definitely a prompt. */
3461                     telnet_recv(rawchar, 0);
3462 #if WIDECHAR
3463 		    inbound_decode_str(xsock->buffer, incomingposttelnet,
3464                         incomingFSM, 0);
3465 #endif
3466 		    handle_socket_input_queue_lines(xsock);
3467 		    queue_socket_line(xsock, CS(xsock->buffer), xsock->buffer->len, F_SERVPROMPT);
3468 		    Stringtrunc(xsock->buffer, 0);
3469                     break;
3470                 case TN_SB:
3471 		    if (!(xsock->flags & SOCKTELNET)) {
3472 			/* Telnet subnegotiation can't happen without a
3473 			 * previous telnet option negotation, so treat the
3474 			 * IAC SB as non-telnet, and disable telnet. */
3475 			xsock->flags &= ~SOCKMAYTELNET;
3476 			place--;
3477 			rawchar = xsock->fsastate;
3478 			goto non_telnet;
3479 		    }
3480                     Sprintf(xsock->subbuffer, "%c%c", TN_IAC, TN_SB);
3481                     xsock->substate = '\0';
3482                     break;
3483                 case TN_WILL: case TN_WONT:
3484                 case TN_DO:   case TN_DONT:
3485                     /* just change state */
3486                     break;
3487                 case TN_IAC:
3488 #if WIDECHAR
3489                     Stringadd(incomingposttelnet, rawchar);  /* literal IAC */
3490 #else
3491                     Stringadd(xsock->buffer, rawchar);  /* literal IAC */
3492 #endif
3493                     xsock->fsastate = '\0';
3494                     break;
3495 
3496                 case TN_NOP:
3497                 case TN_DATA_MARK:
3498                 case TN_BRK:
3499                 case TN_IP:
3500                 case TN_AO:
3501                 case TN_AYT:
3502                 case TN_EC:
3503                 case TN_EL:
3504                     valid = 1;
3505 		    /* Unsupported.  Fall through to default case. */
3506                 default:
3507                     if (xsock->flags & SOCKTELNET ||
3508                         (xsock->flags & SOCKMAYTELNET && valid))
3509                     {
3510                         /* unsupported or invalid telnet command */
3511                         telnet_recv(rawchar, 0);
3512                         xsock->fsastate = '\0';
3513                         break;
3514                     }
3515                     /* Invalid telnet command, and telnet protocol hasn't been
3516                      * established, so treat the IAC and rawchar as non-telnet,
3517                      * and disable telnet. */
3518                     xsock->flags &= ~SOCKMAYTELNET;
3519                     place--;
3520                     rawchar = xsock->fsastate;
3521                     goto non_telnet;
3522                 }
3523 
3524                 if (!(xsock->flags & SOCKTELNET)) {
3525                     /* We now know server groks TELNET */
3526                     xsock->flags |= SOCKTELNET;
3527                     preferred_telnet_options();
3528                 }
3529                 continue;  /* avoid non-telnet processing */
3530 
3531             } else if (xsock->fsastate == TN_SB) {
3532 		if (xsock->subbuffer->len > RECEIVELIMIT) {
3533 		    /* It shouldn't take this long; server is broken.  Abort. */
3534 		    SStringcat(xsock->buffer, CS(xsock->subbuffer));
3535 		    Stringtrunc(xsock->subbuffer, 0);
3536 		} else if (xsock->substate == TN_IAC) {
3537                     if (rawchar == TN_SE) {
3538 			Sappendf(xsock->subbuffer, "%c%c", TN_IAC, TN_SE);
3539                         xsock->fsastate = '\0';
3540                         telnet_subnegotiation();
3541                     } else {
3542                         Stringadd(xsock->subbuffer, rawchar);
3543                         xsock->substate = '\0';
3544                     }
3545                 } else if (rawchar == TN_IAC) {
3546                     xsock->substate = TN_IAC;
3547                 } else {
3548                     Stringadd(xsock->subbuffer, rawchar);
3549                     xsock->substate = '\0';
3550 #if HAVE_MCCP /* hack for broken MCCPv1 subnegotiation */
3551 		    if (xsock->subbuffer->len == 5 &&
3552 			memcmp(xsock->subbuffer->data, mccp1_subneg, 5) == 0)
3553 		    {
3554 			xsock->fsastate = '\0';
3555 			telnet_subnegotiation();
3556 		    }
3557 #endif
3558                 }
3559 #if HAVE_MCCP
3560 		if (xsock->flags & SOCKCOMPRESS && !xsock->zstream) {
3561 		    /* compression was just enabled. */
3562 		    xsock->zstream = new_zstream();
3563 		    if (!xsock->zstream) {
3564 			zombiesock(xsock);
3565 		    } else {
3566 			xsock->zstream->next_in = (Bytef*)++place;
3567 			xsock->zstream->avail_in = count - (place - incoming);
3568 		    }
3569 		    count = 0; /* abort the buffer scan */
3570 		}
3571 #endif
3572                 continue;  /* avoid non-telnet processing */
3573 
3574             } else if (xsock->fsastate == TN_WILL) {
3575                 xsock->fsastate = '\0';
3576                 telnet_recv(TN_WILL, rawchar);
3577                 if (TELOPT(xsock, them, rawchar)) { /* already there, ignore */
3578 		    no_reply("option was already agreed on");
3579                     CLR_TELOPT(xsock, them_tog, rawchar);
3580                 } else if (
3581 #if 0  /* many servers think DO SGA means character-at-a-time mode */
3582                     rawchar == TN_SGA ||
3583 #endif
3584 #if HAVE_MCCP
3585 		    (rawchar == TN_COMPRESS && mccp) ||
3586 		    (rawchar == TN_COMPRESS2 && mccp) ||
3587 #endif
3588 #if ENABLE_ATCP
3589 		    (rawchar == TN_ATCP && atcp) ||
3590 #endif
3591 #if ENABLE_GMCP
3592 		    (rawchar == TN_GMCP && gmcp) ||
3593 #endif
3594 #if ENABLE_OPTION102
3595 		    (rawchar == TN_102 && OPTION102) ||
3596 #endif
3597                     rawchar == TN_ECHO ||
3598                     rawchar == TN_SEND_EOR ||
3599 #if WIDECHAR
3600                     rawchar == TN_CHARSET ||
3601 #endif
3602                     rawchar == TN_BINARY)         /* accept any of these */
3603                 {
3604                     SET_TELOPT(xsock, them, rawchar);  /* set state */
3605                     if (TELOPT(xsock, them_tog, rawchar)) {/* we requested it */
3606                         CLR_TELOPT(xsock, them_tog, rawchar);  /* done */
3607                     } else {
3608                         DO(rawchar);  /* acknowledge their request */
3609                     }
3610                 } else {
3611                     DONT(rawchar);    /* refuse their request */
3612                 }
3613                 continue;  /* avoid non-telnet processing */
3614 
3615             } else if (xsock->fsastate == TN_WONT) {
3616                 xsock->fsastate = '\0';
3617                 telnet_recv(TN_WONT, rawchar);
3618                 if (!TELOPT(xsock, them, rawchar)) { /* already there, ignore */
3619 		    no_reply("option was already agreed on");
3620                     CLR_TELOPT(xsock, them_tog, rawchar);
3621                 } else {
3622                     CLR_TELOPT(xsock, them, rawchar);  /* set state */
3623                     if (TELOPT(xsock, them_tog, rawchar)) { /* we requested */
3624                         CLR_TELOPT(xsock, them_tog, rawchar);  /* done */
3625                     } else {
3626                         DONT(rawchar);  /* acknowledge their request */
3627                     }
3628                 }
3629                 continue;  /* avoid non-telnet processing */
3630 
3631             } else if (xsock->fsastate == TN_DO) {
3632                 xsock->fsastate = '\0';
3633                 telnet_recv(TN_DO, rawchar);
3634                 if (TELOPT(xsock, us, rawchar)) { /* already there, ignore */
3635 		    no_reply("option was already agreed on");
3636                     CLR_TELOPT(xsock, them_tog, rawchar);
3637                 } else if (
3638                     rawchar == TN_NAWS ||
3639                     rawchar == TN_TTYPE ||
3640 #if ENABLE_ATCP
3641 		    (rawchar == TN_ATCP && atcp) ||
3642 #endif
3643                     rawchar == TN_BINARY)
3644                 {
3645                     SET_TELOPT(xsock, us, rawchar);  /* set state */
3646                     if (TELOPT(xsock, us_tog, rawchar)) { /* we requested it */
3647                         CLR_TELOPT(xsock, us_tog, rawchar);  /* done */
3648                     } else {
3649                         WILL(rawchar);  /* acknowledge their request */
3650                     }
3651                     if (rawchar == TN_NAWS) do_naws(xsock);
3652                 } else {
3653                     WONT(rawchar);      /* refuse their request */
3654                 }
3655                 continue;  /* avoid non-telnet processing */
3656 
3657             } else if (xsock->fsastate == TN_DONT) {
3658                 xsock->fsastate = '\0';
3659                 telnet_recv(TN_DONT, rawchar);
3660                 if (!TELOPT(xsock, us, rawchar)) { /* already there, ignore */
3661 		    no_reply("option was already agreed on");
3662                     CLR_TELOPT(xsock, us_tog, rawchar);
3663                 } else {
3664                     CLR_TELOPT(xsock, us, rawchar);  /* set state */
3665                     if (TELOPT(xsock, us_tog, rawchar)) { /* we requested */
3666                         CLR_TELOPT(xsock, us_tog, rawchar);  /* done */
3667                     } else {
3668                         WONT(rawchar);  /* acknowledge their request */
3669                     }
3670                 }
3671                 continue;  /* avoid non-telnet processing */
3672 
3673             } else if (rawchar == TN_IAC &&
3674                 xsock->flags & (SOCKTELNET | SOCKMAYTELNET))
3675             {
3676                 xsock->fsastate = TN_IAC;
3677                 continue;  /* avoid non-telnet processing */
3678             }
3679 
3680             /* non-telnet processing*/
3681 non_telnet:
3682 	    /* This is char-by-char. Very inefficient. */
3683 #if WIDECHAR
3684 	    Stringadd(incomingposttelnet, rawchar);
3685 #else
3686             Stringadd(xsock->buffer, rawchar);
3687 #endif
3688 	    if (rawchar == '\r' || rawchar == '\n' || rawchar == '*')
3689 		xsock->fsastate = rawchar;
3690 	    else
3691 		xsock->fsastate = '\0';
3692 	} /* End of buffer-scanning for-loop */
3693 	    /* No premature optimization; Too much to go wrong.
3694 	    const char *end;
3695 	    if (xsock->flags & (SOCKTELNET | SOCKMAYTELNET)) {
3696 	        end = place++;
3697 	        while (end - buffer < count && *end != TN_IAC)
3698 	          ++end;
3699 #if WIDECHAR
3700 		Stringfncat(incomingposttelnet, place, end - place);
3701 #else
3702 		Stringfncat(xsock->buffer, place, end - place);
3703 #endif
3704 		xsock->fsastate = *end;
3705 	    } else {
3706 	        end = buffer + count;
3707 	    }
3708 */
3709 #if WIDECHAR
3710 	/* Take incomingposttelnet and convert to UTF-8, writing to
3711          * xsock->buffer. Shift incomingposttelnet by length converted.
3712          * Data CAN be left over. */
3713         inbound_decode_str(xsock->buffer, incomingposttelnet, incomingFSM, 0);
3714 #endif
3715         /* Non-WIDECHAR just writes to xsock->buffer.
3716         Stringcpy(xsock->buffer, incomingposttelnet);
3717         Stringtrunc(incomingposttelnet, 0);
3718         */
3719 	/* Start walking xsock->buffer, which only contains valid UTF-8 */
3720 	handle_socket_input_queue_lines(xsock);
3721 
3722         /* See if anything arrived while we were parsing */
3723 
3724 	received += count;
3725 
3726 #if HAVE_MCCP
3727 	/* If there's still un-inflated stuff, we must process it before we
3728 	 * exit this loop.
3729 	 */
3730 	if (xsock->zstream && xsock->zstream->avail_in) {
3731 	    n = xsock->zstream->avail_in;
3732 	    continue;
3733 	}
3734 #endif
3735 
3736 	if (simbuffer || received > SPAM) break; /* after uninflated check */
3737 
3738         FD_ZERO(&readfds);
3739         FD_SET(xsock->fd, &readfds);
3740 	timeout = tvzero; /* don't use tvzero directly, select may modify it */
3741         if ((n = select(xsock->fd + 1, &readfds, NULL, NULL, &timeout)) < 0) {
3742             if (errno != EINTR) die("handle_socket_input: select", errno);
3743         }
3744 
3745 	if (interrupted()) break;
3746 
3747     } while (n > 0);
3748 
3749     test_prompt();
3750 
3751     return received;
3752 }
3753 
3754 /* This function CAN leave data in sock->buffer */
3755 STATIC_BUFFER(nextline); /* Static for speed */
handle_socket_input_queue_lines(Sock * sock)3756 static void handle_socket_input_queue_lines(Sock *sock)
3757 {
3758     String *debug = sock->buffer;
3759     char *place;
3760     char *bufferend = sock->buffer->data + sock->buffer->len;
3761     char rawchar, localchar;
3762     char lastchar = '\0';
3763     for (place = sock->buffer->data; place != bufferend; ++place) {
3764         /* We always accept 8-bit data, even though RFCs 854 and 1123
3765          * say server shouldn't transmit it unless in BINARY mode.  What
3766          * we do with it depends on the locale.
3767          */
3768         rawchar = *place;
3769         localchar = localize(rawchar); /* NOP if WIDECHAR defined */
3770         if (rawchar == '\n') {
3771             /* Complete line received.  Queue it. */
3772             queue_socket_line(sock, CS(nextline), nextline->len, 0);
3773             /* Shift to one past the end. */
3774             Stringshift(sock->buffer, place - sock->buffer->data + 1);
3775             Stringtrunc(nextline, 0);
3776             place = sock->buffer->data - 1;
3777             bufferend = sock->buffer->data + sock->buffer->len;
3778 
3779         } else if (emulation == EMUL_DEBUG) {
3780             if (localchar != rawchar)
3781                 Stringcat(nextline, "M-");
3782             if (is_print(localchar))
3783                 Stringadd(nextline, localchar);
3784             else {
3785                 Stringadd(nextline, '^');
3786                 Stringadd(nextline, CTRL(localchar));
3787             }
3788 
3789         } else if (rawchar == '\r' || rawchar == '\0') {
3790             /* Ignore CR and NUL. */
3791 
3792         } else if (rawchar == '\b' && emulation >= EMUL_PRINT &&
3793             lastchar == '*')
3794         {
3795             /* "*\b" is an LP editor prompt. */
3796             queue_socket_line(sock, CS(nextline), nextline->len, F_SERVPROMPT);
3797             Stringshift(sock->buffer, place - sock->buffer->data + 1);
3798             Stringtrunc(nextline, 0);
3799             place = sock->buffer->data - 1;
3800             bufferend = sock->buffer->data + sock->buffer->len;
3801             /* other occurances of '\b' are handled by decode_ansi(), so
3802             * ansi codes aren't clobbered before they're interpreted */
3803 
3804         } else {
3805             /* Explicitly pop the first byte so we can't get stuck. */
3806             Stringadd(nextline, localchar);
3807             char *end;
3808             end = ++place;
3809             /* Quickly skip characters that can't possibly be special. */
3810 #if WIDECHAR
3811             while (end != bufferend && *end != '\n' && *end != '\r' &&
3812                 *end != '\0' && *end != '\b' && *end != '*')
3813 #else
3814             while (end != bufferend && is_print(*end) && *end != TN_IAC)
3815 #endif
3816                 ++end;
3817             Stringfncat(nextline, place, end - place);
3818             place = end - 1;
3819         }
3820         lastchar = *place;
3821     } /* End of buffer-scanning for-loop */
3822     /* Shouldn't need to be here, but last lines get duplicated otherwise. */
3823     /* This implies something is wrong. */
3824     Stringtrunc(nextline, 0);
3825 }
3826 
is_quiet(const char * str)3827 static int is_quiet(const char *str)
3828 {
3829     if (!xsock->numquiet) return 0;
3830     if (!--xsock->numquiet) return 1;
3831     /* This should not be hard coded. */
3832     if ((strncmp("Use the WHO command", str, 19) == 0) ||
3833         (strcmp("### end of messages ###", str) == 0))
3834             xsock->numquiet = 0;
3835     return 1;
3836 }
3837 
is_bamf(const char * str)3838 static int is_bamf(const char *str)
3839 {
3840     smallstr name, host, port;
3841     STATIC_BUFFER(buffer);
3842     World *world;
3843     Sock *callingsock;  /* like find_and_run_matches(), we must restore xsock */
3844 
3845     callingsock = xsock;
3846 
3847     if (!bamf || restriction >= RESTRICT_WORLD) return 0;
3848     if (sscanf(str,
3849         "#### Please reconnect to %64[^ @]@%64s (%*64[^ )]) port %64s ####",
3850         name, host, port) != 3)
3851             return 0;
3852 
3853     Stringtrunc(buffer, 0);
3854     if (bamf == BAMF_UNTER) Stringadd(buffer, '@');
3855     Stringcat(buffer, name);
3856     if (!(world = find_world(buffer->data))) {
3857         if (bamf == BAMF_UNTER && xsock) {
3858             world = new_world(buffer->data, xsock->world->type,
3859 		host, port, xsock->world->character, xsock->world->pass,
3860 		xsock->world->mfile, WORLD_TEMP, xsock->world->myhost);
3861         } else {
3862             world = new_world(buffer->data,"",host,port,"","","",WORLD_TEMP,"");
3863         }
3864     }
3865 
3866     do_hook(H_BAMF, "%% Bamfing to %s", "%s", name);
3867     if (bamf == BAMF_UNTER && xsock) killsock(xsock);
3868     if (!opensock(world, CONN_AUTOLOGIN))
3869         eputs("% Connection through portal failed.");
3870     xsock = callingsock;
3871     return 1;
3872 }
3873 
do_naws(Sock * sock)3874 static void do_naws(Sock *sock)
3875 {
3876     unsigned int width, height, i;
3877     UCHAR octet[4];
3878     Sock *old_xsock;
3879 
3880     width = (emulation != EMUL_RAW && wrapflag && wrapsize) ?
3881 	wrapsize : columns;
3882     height = winlines() + !visual;
3883 
3884     Sprintf(telbuf, "%c%c%c", TN_IAC, TN_SB, TN_NAWS);
3885     octet[0] = (width >> 8);
3886     octet[1] = (width & 0xFF);
3887     octet[2] = (height >> 8);
3888     octet[3] = (height & 0xFF);
3889     for (i = 0; i < 4; i++) {
3890         if (octet[i] == (UCHAR)TN_IAC) Stringadd(telbuf, TN_IAC);
3891         Stringadd(telbuf, octet[i]);
3892     }
3893     Sappendf(telbuf, "%c%c", TN_IAC, TN_SE);
3894 
3895     old_xsock = xsock;;
3896     xsock = sock;
3897     telnet_send(telbuf);
3898     xsock = old_xsock;
3899 }
3900 
telnet_debug(const char * dir,const char * str,int len)3901 static void telnet_debug(const char *dir, const char *str, int len)
3902 {
3903     String *buffer;
3904     int state;
3905 
3906     if (telopt) {
3907         buffer = Stringnew(NULL, 0, 0);
3908         Sprintf(buffer, "%% %s:", dir);
3909 	if (len == 0)
3910 	    Stringcat(buffer, str);
3911 	else {
3912 	    for (state = 0; len; len--, str++) {
3913 		if (*str == TN_IAC || state == TN_IAC || state == TN_SB ||
3914 		    state == TN_WILL || state == TN_WONT ||
3915 		    state == TN_DO || state == TN_DONT)
3916 		{
3917 		    if (telnet_label[(UCHAR)*str])
3918 			Sappendf(buffer, " %s", telnet_label[(UCHAR)*str]);
3919 		    else
3920 			Sappendf(buffer, " %d", (unsigned int)*str);
3921 		    state = *str;
3922 		} else if (state == TN_TTYPE) {
3923 		    if (*str == (char)0) {
3924 			Stringcat(buffer, " IS \"");
3925 			while (len--, str++, is_print(*str) && !(*str & 0x80))
3926 			    Stringadd(buffer, *str);
3927 			Stringadd(buffer, '\"');
3928 			len++, str--;
3929 		    } else if (*str == (char)1) {
3930 			Stringcat(buffer, " SEND");
3931 		    }
3932 		    state = 0;
3933 		} else if (state == TN_CHARSET) {
3934 		    if (*str == (char)1) {
3935 			Stringcat(buffer, " REQUEST ");
3936 			while (len--, str++, is_print(*str) && !(*str & 0x80))
3937 			    Stringadd(buffer, *str);
3938 			len++, str--;
3939 		    } else if (*str == (char)2) {
3940 			Stringcat(buffer, " ACCEPTED ");
3941 			while (len--, str++, is_print(*str) && !(*str & 0x80))
3942 			    Stringadd(buffer, *str);
3943 			len++, str--;
3944 		    } else if (*str == (char)3) {
3945 			Stringcat(buffer, " REJECTED");
3946 		    }
3947 		    state = 0;
3948 		} else {
3949 		    Sappendf(buffer, " %u", (unsigned char)*str);
3950 		    state = 0;
3951 		}
3952 	    }
3953 	}
3954         nolog++;
3955         /* norecord++; */
3956         world_output(xsock->world, CS(buffer));
3957         /* norecord--; */
3958         nolog--;
3959     }
3960 }
3961 
telnet_send(String * cmd)3962 static void telnet_send(String *cmd)
3963 {
3964     transmit(cmd->data, cmd->len);
3965     telnet_debug("sent", cmd->data, cmd->len);
3966 }
3967 
local_echo(int flag)3968 int local_echo(int flag)
3969 {
3970     if (flag < 0)
3971         return sockecho();
3972     if (!xsock || !(xsock->flags & SOCKTELNET))
3973         return 0;
3974 
3975     if (flag != sockecho()) {
3976         /* request a change */
3977         SET_TELOPT(xsock, them_tog, TN_ECHO);
3978         if (flag)
3979             DONT(TN_ECHO);
3980         else
3981             DO(TN_ECHO);
3982     }
3983     return 1;
3984 }
3985 
3986 
transmit_window_size(void)3987 void transmit_window_size(void)
3988 {
3989     Sock *sock;
3990 
3991     for (sock = hsock; sock; sock = sock->next)
3992         if (TELOPT(sock, us, TN_NAWS))
3993             do_naws(sock);
3994 }
3995 
preferred_telnet_options(void)3996 static void preferred_telnet_options(void)
3997 {
3998     SET_TELOPT(xsock, us_tog, TN_NAWS);
3999     WILL(TN_NAWS);
4000 #if 0
4001     SET_TELOPT(xsock, us_tog, TN_BINARY);
4002     WILL(TN_BINARY);		/* allow us to send 8-bit data */
4003     SET_TELOPT(xsock, them_tog, TN_BINARY);
4004     DO(TN_BINARY);		/* allow server to send 8-bit data */
4005 #endif
4006 }
4007 
4008 /* Find the named world (current world if name is blank) or print an error */
named_or_current_world(const char * name)4009 World *named_or_current_world(const char *name)
4010 {
4011     World *world;
4012     if (!(world = (*name) ? find_world(name) : xworld())) {
4013 	eprintf("No world %s", name);
4014     }
4015     return world;
4016 }
4017 
world_info(const char * worldname,const char * fieldname)4018 const char *world_info(const char *worldname, const char *fieldname)
4019 {
4020     World *world;
4021     const char *result;
4022 
4023     world = worldname ? find_world(worldname) : xworld();
4024     if (!world) return ""; /* not an error */
4025 
4026     if (!fieldname || strcmp("name", fieldname) == 0) {
4027         result = world->name;
4028     } else if (strcmp("type", fieldname) == 0) {
4029         result = world_type(world);
4030     } else if (strcmp("character", fieldname) == 0) {
4031         result = world_character(world);
4032     } else if (strcmp("password", fieldname) == 0) {
4033         result = world_pass(world);
4034     } else if (strcmp("host", fieldname) == 0) {
4035         result = worldname ? world->host : world->sock->host;
4036     } else if (strcmp("port", fieldname) == 0) {
4037         result = worldname ? world->port : world->sock->port;
4038     } else if (strcmp("mfile", fieldname) == 0) {
4039         result = world_mfile(world);
4040     } else if (strcmp("login", fieldname) == 0) {
4041         result = world->sock && world->sock->flags & SOCKLOGIN ? "1" : "0";
4042     } else if (strcmp("proxy", fieldname) == 0) {
4043         result = world->sock && world->sock->flags & SOCKPROXY ? "1" : "0";
4044     } else if (strcmp("src", fieldname) == 0) {
4045         result = worldname ? world->myhost : world->sock->myhost;
4046     } else if (strcmp("cipher", fieldname) == 0) {
4047 	result =
4048 #if HAVE_SSL
4049 	    (world->sock && world->sock->ssl) ?
4050 	    SSL_get_cipher_name(world->sock->ssl) :
4051 #endif
4052 	    "";
4053     } else return NULL;
4054     return result ? result : "";
4055 }
4056 
is_open(const char * worldname)4057 int is_open(const char *worldname)
4058 {
4059     World *w;
4060 
4061     if (!worldname || !*worldname) {
4062         if (!xsock) return 0;
4063         w = xsock->world;
4064     } else if (!(w = find_world(worldname))) {
4065         return 0;
4066     }
4067     return (w->sock && (w->sock->constate >= SS_CONNECTED) &&
4068 	(w->sock->constate < SS_ZOMBIE));
4069 }
4070 
is_connected(const char * worldname)4071 int is_connected(const char *worldname)
4072 {
4073     World *w;
4074 
4075     if (!worldname || !*worldname) {
4076         if (!xsock) return 0;
4077         w = xsock->world;
4078     } else if (!(w = find_world(worldname))) {
4079         return 0;
4080     }
4081     return (w->sock && (w->sock->constate == SS_CONNECTED));
4082 }
4083 
nactive(const char * worldname)4084 int nactive(const char *worldname)
4085 {
4086     World *w;
4087 
4088     if (!worldname || !*worldname)
4089         return active_count;
4090     if (!(w = find_world(worldname)) || !w->sock)
4091         return 0;
4092     return w->screen->active ? w->screen->nnew : 0;
4093 }
4094