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