Standards-Version: 3.9.6 (no changes)
[ckermit.git] / ckcnet.c
1 char *cknetv = "Network support, 9.0.297, 14 Jul 2011";
2
3 /*  C K C N E T  --  Network support  */
4
5 /*
6   Copyright (C) 1985, 2011,
7     Trustees of Columbia University in the City of New York.
8     All rights reserved.  See the C-Kermit COPYING.TXT file or the
9     copyright text in the ckcmai.c module for disclaimer and permissions.
10 */
11
12 /*
13   REMINDER: Any changes made to this file that other modules depend must
14   also be made to cklnet.c (for VOS) until such time as cklnet.c and this
15   module are merged back together.
16
17   NOTE TO CONTRIBUTORS: This file, and all the other shared (ckc and cku)
18   C-Kermit source files, must be compatible with C preprocessors that support
19   only #ifdef, #else, #endif, #define, and #undef.  Please do not use #if,
20   logical operators, or other preprocessor features in this module.  Also,
21   don't use any ANSI C constructs except within #ifdef CK_ANSIC..#endif.
22
23   Authors:
24
25   Frank da Cruz (fdc@columbia.edu),
26     Columbia University Academic Information Systems, New York City.
27   Jeffrey E Altman (jaltman@secure-endpoints.com) -- Primary 
28     maintainer/developer since about 1996.
29   netopen() routine for TCP/IP originally by Ken Yap, Rochester University
30     (ken@cs.rochester.edu) (no longer at that address).
31   Missing pieces for Excelan sockets library from William Bader.
32   Telnet protocol by Frank da Cruz and Jeffrey Altman.
33   Rlogin protocol by Jeffrey E Altman.
34   SSL support adapted by Jeffrey E Altman from work done by
35     Tim Hudson <tjh@cryptosoft.com> +61 7 32781581
36   TLS support by Jeffrey E Altman.
37   HTTP support by Jeffrey E Altman.
38   TGV MultiNet code by Frank da Cruz.
39   MultiNet code adapted to WIN/TCP by Ray Hunter of TWG.
40   MultiNet code adapted to DEC TCP/IP by Lee Tibbert of DEC and Frank da Cruz.
41   TCP/IP support adapted to IBM TCP/IP 1.2.1,2.0 for OS/2 by Kai Uwe Rommel.
42   CMU-OpenVMS/IP modifications by Mike O'Malley, Digital (DEC).
43   X.25 support by Marcello Frutig, Catholic University,
44     Rio de Janeiro, Brazil (frutig@rnp.impa.br) with fixes from
45     Stefaan Eeckels, Eurokom, Luxembourg.
46     David Lane added support for Stratus VOS X.25 1996.
47     Stephen Riehm added support for IBM AIX X.25 in April 1998.
48   Other contributions as indicated in the code.
49 */
50 #define CKCNET_C
51 #include "ckcsym.h"
52 #include "ckcdeb.h"
53 #include "ckcker.h"
54 #include "ckcasc.h"
55 #ifdef I386IX                           /* Has to come before ckcnet.h in */
56 #include <errno.h>                      /* this version, but after in others */
57 #endif /* I386IX */
58 #include "ckcnet.h"                     /* which includes ckctel.h */
59 #ifdef CK_SSL
60 #include "ck_ssl.h"
61 #endif /* CK_SSL */
62
63 #ifdef CK_DNS_SRV
64 #ifdef OS2
65 #ifdef NT
66 #include <wshelper.h>
67 #else /* NT */
68 /* !Error OS/2 does not support DNS Service Records. */
69 #endif /* NT */
70 #else /* OS2 */
71 #include <arpa/inet.h>
72 #ifdef USE_NAMESER_COMPAT
73 #include <arpa/nameser_compat.h>
74 #endif  /* USE_NAMESER_COMPAT */
75
76 #ifdef MINIX3
77 #include <net/gen/resolv.h>
78 #include <net/gen/nameser.h>
79 #else
80 #include <arpa/nameser.h>
81 #include <resolv.h>
82 #endif /* MINIX 3 */
83
84 #ifndef PS2AIX10
85 #ifndef BSD4
86 #ifndef I386IX
87 #ifndef RTAIX
88 #include <netdb.h>
89 #endif /* RTAIX */
90 #endif /* I386IX */
91 #endif /* BSD4 */
92 #endif /* PS2AIX10 */
93 #endif /* OS2 */
94 #ifndef T_SRV
95 #define T_SRV 33
96 #endif /* T_SRV */
97 #ifndef T_TXT
98 #define T_TXT 16
99 #endif /* T_TXT */
100
101 /* for old Unixes and friends ... */
102 #ifndef MAXHOSTNAMELEN
103 #define MAXHOSTNAMELEN 64
104 #endif /* MAXHOSTNAMELEN */
105
106 #define MAX_DNS_NAMELEN (15*(MAXHOSTNAMELEN + 1)+1)
107 #endif /* CK_DNS_SRV */
108
109 #ifdef NONET
110 #ifdef TCPIPLIB
111 #undef TCPIPLIB
112 #endif /* TCPIPLIB */
113 #endif /* NONET */
114
115 #ifndef NOMHHOST
116 #ifdef datageneral
117 #define NOMHHOST
118 #else
119 #ifdef HPUX5WINTCP
120 #define NOMHHOST
121 #endif /* HPUX5WINTCP */
122 #endif /* datageneral */
123 #endif /* NOMHHOST */
124
125 #ifdef INADDRX
126   struct in_addr inaddrx;
127 #endif /* INADDRX */
128
129 int ttnet = NET_NONE;                   /* Network type */
130 int ttnproto = NP_DEFAULT;              /* Network virtual terminal protocol */
131
132 /* 0 = don't lowercase username for Rlogin/Telnet protocol */
133 /* nonzero = do lowercase it.  Add a SET command if necessary... */
134 #ifdef VMS
135 int ck_lcname = 1;
136 #else
137 int ck_lcname = 0;
138 #endif /* VMS */
139
140 extern int                              /* External variables */
141   duplex, debses, seslog, sessft, wasclosed,
142   ttyfd, quiet, msgflg, what, nettype, ttmdm;
143 #ifdef IKSD
144 extern int inserver;
145 #endif /* IKSD */
146
147 char myipaddr[20] = { '\0' };           /* Global copy of my IP address */
148 char hostipaddr[64] = { '\0' };         /* Global copy of remote IP address */
149
150 #ifdef NETCONN
151 /* Don't need any of this if there is no network support. */
152
153 #ifndef OS2
154 /* Current fd-swapping hack is not thread-safe */
155 #define HTTP_BUFFERING
156 #endif  /* OS2 */
157
158 #ifdef HTTP_BUFFERING
159 #define HTTP_INBUFLEN 8192
160 static char http_inbuf[HTTP_INBUFLEN];
161 static int http_bufp = 0, http_count;
162 #endif  /* HTTP_BUFFERING */
163
164 /*
165   NETLEBUF is (must be) defined for those platforms that call this
166   module to do network i/o (e.g. netinc(), nettchk(), etc) rather
167   than doing it themselves (ttinc(), ttchk(), etc).  In this case
168   the Telnet local-echo buffers and routines are defined and referenced
169   here, rather than in the ck?tio.c module.
170 */
171 #ifdef NETLEBUF
172 #define LEBUFSIZ 4096
173 int ttpush = -1, le_data = 0;           /* These are seen from outside */
174 static CHAR le_buf[LEBUFSIZ];           /* These are used internally */
175 static int le_start = 0, le_end = 0;
176 int tt_push_inited = 0;
177 #endif /* NETLEBUF */
178
179 #ifdef CK_SOCKS                         /* SOCKS Internet relay package */
180 #ifdef CK_SOCKS5                        /* SOCKS 5 */
181 #define accept  SOCKSaccept
182 #define bind    SOCKSbind
183 #define connect SOCKSconnect
184 #define getsockname SOCKSgetsockname
185 #define listen SOCKSlisten
186 #else  /* Not SOCKS 5 */
187 #define accept  Raccept
188 #define bind    Rbind
189 #define connect Rconnect
190 #define getsockname Rgetsockname
191 #define listen Rlisten
192 #endif /* CK_SOCKS5 */
193 #endif /* CK_SOCKS */
194
195 #ifdef DEC_TCPIP
196 #include <time.h>
197 #include <inet.h>
198 #endif /* DEC_TCPIP */
199
200 /* Also see ckcnet.h -- hmmm, why don't we always include inet.h? */
201
202 #ifdef HPUX
203 #ifndef HPUX7                           /* HPUX 7.00 doesn't have it */
204 #ifndef HPUX6                           /* HPUX 6.00 doesn't have it */
205 #include <arpa/inet.h>                  /* For inet_ntoa() prototype */
206 #endif /* HPUX6 */
207 #endif /* HPUX7 */
208 #endif /* HPUX */
209
210 #ifdef CMU_TCPIP
211 #include <time.h>
212 #endif /* CMU_TCPIP */
213
214 #ifndef NODCLTIMEVAL
215 #ifdef DCLTIMEVAL                       /* UnixWare 7 */
216 struct timeval {                        /* And define these ourselves. */
217     long tv_sec;                        /* (see comments in ckutio.c) */
218     long tv_usec;
219 };
220 struct timezone {
221     int tz_minuteswest;
222     int tz_dsttime;
223 };
224 #endif /* DCLTIMEVAL */
225 #endif /* NODCLTIMEVAL */
226
227 #ifdef WINTCP
228
229 #include <setjmp.h>
230 #include <signal.h>
231 #include <sys/time.h>
232 /*
233   The WIN/TCP code path is the same as that for MultiNet.
234   Only the routine names have changed ...
235 */
236 #define socket_read     netread
237 #define socket_ioctl    ioctl
238 #define socket_write    netwrite
239 #define socket_close    netclose
240
241 #ifdef OLD_TWG                         /* some routines have evolved */
242         extern int vmserrno, uerrno;
243 #define socket_errno    uerrno
244 #define socket_perror   perror         /* which uses errno, not uerrno! */
245 #else
246 #define socket_errno    errno
247 #define socket_perror   win$perror
248 #endif /* OLD_TWG */
249
250 #else /* Not WINTCP */
251
252 #ifdef OSF13
253 #ifdef CK_ANSIC
254 #ifdef _NO_PROTO
255 #undef _NO_PROTO
256 #endif /* _NO_PROTO */
257 #endif /* CK_ANSIC */
258 #endif /* OSF13 */
259
260 #ifndef I386IX
261 #ifndef HPUXPRE65
262 #include <errno.h>                      /* Error number symbols */
263 #else
264 #ifndef ERRNO_INCLUDED
265 #include <errno.h>                      /* Error number symbols */
266 #endif  /* ERRNO_INCLUDED */
267 #endif  /* HPUXPRE65 */
268 #endif /* I386IX */
269
270 #include <signal.h>                     /* Everybody needs this */
271
272 #ifdef ZILOG                            /* Zilog has different name for this */
273 #include <setret.h>
274 #else
275 #include <setjmp.h>
276 #endif /* ZILOG */
277
278 #endif /* WINTCP */
279
280 #ifdef datageneral                      /* Data General AOS/VS */
281 #include <:usr:include:vs_tcp_errno.h>
282 #include <:usr:include:sys:vs_tcp_types.h>
283 #ifdef SELECT
284 /*
285   NOTE: This can be compiled and linked OK with SELECT defined
286   but it doesn't work at all.  Anybody who cares and knows how
287   to fix it, feel free.
288 */
289 #include <:usr:include:sys:vs_tcp_time.h>
290 #endif /* SELECT */
291 #include <:usr:include:sys:socket.h>
292 #include <:usr:include:netinet:in.h>
293 #include <:usr:include:netdb.h>
294 #endif /* datageneral */
295
296 #ifndef socket_errno
297 #define socket_errno errno
298 #endif /* socket_errno */
299
300 #ifdef TNCODE
301 extern int tn_deb;
302 #endif /* TNCODE */
303
304 int tcp_rdns =                          /* Reverse DNS lookup */
305 #ifdef DEC_TCPIP_OLD
306     SET_OFF                             /* Doesn't seem to work in UCX */
307 #else
308      SET_AUTO
309 #endif /* DEC_TCPIP */
310       ;
311 #ifdef CK_DNS_SRV
312 int tcp_dns_srv = SET_OFF;
313 #endif /* CK_DNS_SRV */
314
315 _PROTOTYP( char * cmcvtdate, (char *, int) );
316
317 #ifdef RLOGCODE
318 _PROTOTYP( int rlog_ctrl, (CHAR *, int) );
319 _PROTOTYP( static int rlog_oob, (CHAR *, int) );
320 #ifndef TCPIPLIB
321 _PROTOTYP( static SIGTYP rlogoobh, ( int ) );
322 #endif /* TCPIPLIB */
323 _PROTOTYP( static int rlog_ini, (CHAR *, int,
324                                  struct sockaddr_in *,
325                                  struct sockaddr_in *) );
326 int rlog_mode = RL_COOKED;
327 int rlog_stopped = 0;
328 int rlog_inband = 0;
329 #endif /* RLOGCODE */
330
331 #ifndef NOICP
332 extern int doconx;                      /* CONNECT-class command active */
333 #endif /* NOICP */
334
335 #ifdef IBMX25
336 /* This variable should probably be generalised for true client/server
337  * support - ie: the fd of the listening server, accepted calls should
338  * be forked or at least handled via a second fd (for IBM's X.25 -
339  * ttyfd always holds the active fd - ie the server becomes inactive
340  * as long as a client is connected, and becomes active again when the
341  * connection is closed)
342  */
343 int x25serverfd = 0;            /* extern in ckcnet.h */
344 int x25seqno = 0;               /* Connection sequence number */
345 int x25lastmsg = -1;            /* A cheapskate's state table */
346
347 #define X25_CLOSED      0       /* Default state: no connection, no STREAM */
348 #define X25_SETUP       1       /* X.25 has been set up (no connection) */
349 #define X25_CONNECTED   2       /* X.25 connection has been established */
350 int x25_state = X25_CLOSED;     /* Default state */
351 #endif /* IBMX25 */
352
353 #ifndef DEBUG
354 #define deblog 0
355 #endif /* DEBUG */
356
357 #ifdef CK_NAWS                          /* Negotiate About Window Size */
358 #ifdef RLOGCODE
359 _PROTOTYP( int rlog_naws, (void) );
360 #endif /* RLOGCODE */
361 #endif /* CK_NAWS */
362
363 #ifdef OS2                              /* For terminal type name string */
364 #include "ckuusr.h"
365 #ifndef NT
366 #include <os2.h>
367 #undef COMMENT
368 #endif /* NT */
369 #include "ckocon.h"
370 extern int tt_type, max_tt;
371 extern struct tt_info_rec tt_info[];
372 extern char ttname[];
373 #else
374 #ifdef CK_AUTHENTICATION
375 #include "ckuusr.h"
376 #endif /* CK_AUTHENTICATION */
377 #endif /* OS2 */
378
379 #ifdef NT
380 extern int winsock_version;
381 #endif /* NT */
382
383 #ifdef CK_AUTHENTICATION
384 #include "ckuath.h"
385 #endif /* CK_AUTHENTICATION */
386
387 #include "ckcsig.h"
388
389 #ifndef OS2                             /* For timeout longjumps */
390 static ckjmpbuf njbuf;
391 #endif /* OS2 */
392
393 #define NAMECPYL 1024                   /* Local copy of hostname */
394 char namecopy[NAMECPYL];                /* Referenced by ckctel.c */
395 char namecopy2[NAMECPYL];               /* Referenced by ckctel.c */
396 #ifndef NOHTTP
397 char http_host_port[NAMECPYL];          /* orig host/port necessary for http */
398 char http_ip[20] = { '\0' };            /* ip address of host */
399 char http_port = 0;
400 int  http_ssl = 0;
401 char * http_agent = 0;
402 int  httpfd = -1;                       /* socket for http connections */
403 int  http_code = 0;
404 #define HTTPBUFLEN  1024
405 char http_reply_str[HTTPBUFLEN] = "";
406 #endif /* NOHTTP */
407
408 char ipaddr[20] = { '\0' };             /* Global copy of IP address */
409 unsigned long myxipaddr = 0L;           /* Ditto as a number */
410 #endif /* NETCONN */
411
412 char *tcp_address = NULL;               /* Preferred IP Address */
413 extern char uidbuf[];                   /* User ID buffer */
414 extern char pwbuf[];                    /* Password buffer */
415
416 #ifndef NOHTTP
417 char * tcp_http_proxy = NULL;           /* Name[:port] of http proxy server */
418 int    tcp_http_proxy_errno = 0;
419 char * tcp_http_proxy_user = NULL;
420 char * tcp_http_proxy_pwd  = NULL;
421 char * tcp_http_proxy_agent = NULL;
422 #define HTTPCPYL 1024
423 static char proxycopy[HTTPCPYL];
424 #endif /* NOHTTP */
425
426 #ifdef OS2
427 extern int tt_rows[], tt_cols[];
428 extern int tt_status[VNUM];
429 #else /* OS2 */
430 extern int tt_rows, tt_cols;            /* Everybody has this */
431 #endif /* OS2 */
432
433 extern int cmd_cols, cmd_rows;
434
435 #ifdef STREAMING                        /* Use blocking writes for streaming */
436 extern int streaming;
437 #endif /* STREAMING */
438
439 #ifdef NT
440 extern int WSASafeToCancel;
441 int win95selectbug = 0;                 /* For TCP/IP stacks whose select() */
442 /* always fails on write requests such as Cisco and Quarterdeck */
443 #define stricmp _stricmp
444 #endif /* NT */
445
446 #ifndef NOTCPOPTS
447
448 /* Skip all this if NOTCPOPTS specified. */
449
450 #ifdef SOL_SOCKET
451
452 #ifdef TCP_NODELAY
453 int tcp_nodelay = 0;                    /* Nagle algorithm TCP_NODELAY */
454 #endif /* TCP_NODELAY */
455
456 #ifdef SO_DONTROUTE
457 int tcp_dontroute = 0;
458 #endif /* SO_DONTROUTE */
459
460 #ifdef SO_LINGER
461 int tcp_linger  = 0;                    /* SO_LINGER */
462 int tcp_linger_tmo = 0;                 /* SO_LINGER timeout */
463 #endif /* SO_LINGER */
464
465 #ifdef HPUX                             /* But the data structures */
466 #ifndef HPUX8                           /* needed for linger are not */
467 #ifndef HPUX9                           /* defined in HP-UX versions */
468 #ifndef HPUX10                          /* prior to 8.00. */
469 #ifdef SO_LINGER
470 #undef SO_LINGER
471 #endif /* SO_LINGER */
472 #endif /* HPUX10 */
473 #endif /* HPUX9 */
474 #endif /* HPUX8 */
475 #endif /* HPUX */
476
477 #ifndef SO_OOBINLINE                    /* Hopefully only HP-UX 7.0 */
478 #define SO_OOBINLINE 0x0100
479 #endif /* SO_OOBINLINE */
480
481 #ifndef TCPSNDBUFSIZ
482 #ifdef VMS
483 #ifdef __alpha
484 #define TCPSNDBUFSIZ 16384
485 #endif /* __alpha */
486 #endif /* VMS */
487 #endif /* TCPSNDBUFSIZ */
488
489 #ifndef TCPSNDBUFSIZ
490 #define TCPSNDBUFSIZ -1
491 #endif /* TCPSNDBUFSIZ */
492
493 #ifdef SO_SNDBUF
494 int tcp_sendbuf = TCPSNDBUFSIZ;
495 #endif /* SO_SNDBUF */
496
497 #ifdef SO_RCVBUF
498 int tcp_recvbuf = -1;
499 #endif /* SO_RCVBUF */
500
501 #ifdef SO_KEEPALIVE
502 int tcp_keepalive = 1;
503 #endif /* SO_KEEPALIVE */
504
505 #endif /* SOL_SOCKET */
506 #endif /* NOTCPOPTS */
507
508 #ifndef NETCONN
509 /*
510   Network support not defined.
511   Dummy functions here in case #ifdef's forgotten elsewhere.
512 */
513 int                                     /* Open network connection */
514 netopen(name, lcl, nett) char *name; int *lcl, nett; {
515     return(-1);
516 }
517 int                                     /* Close network connection */
518 netclos() {
519     return(-1);
520 }
521 int                                     /* Check network input buffer */
522 nettchk() {
523     return(-1);
524 }
525 int                                     /* Flush network input buffer */
526 netflui() {
527     return(-1);
528 }
529 int                                     /* Send network BREAK */
530 netbreak() {
531     return(-1);
532 }
533 int                                     /* Input character from network */
534 netinc(timo) int timo; {
535     return(-1);
536 }
537 int                                     /* Output character to network */
538 #ifdef CK_ANSIC
539 nettoc(CHAR c)
540 #else
541 nettoc(c) CHAR c;
542 #endif /* CK_ANSIC */
543 /* nettoc */ {
544     return(-1);
545 }
546 int
547 nettol(s,n) CHAR *s; int n; {
548     return(-1);
549 }
550
551 #else /* NETCONN is defined (much of this module...) */
552
553 #ifdef NETLEBUF
554 VOID
555 le_init() {                             /* LocalEchoInit() */
556     int i;
557     for (i = 0; i < LEBUFSIZ; i++)
558       le_buf[i] = '\0';
559     le_start = 0;
560     le_end = 0;
561     le_data = 0;
562     tt_push_inited = 1;
563 }
564
565 VOID
566 le_clean() {                            /* LocalEchoCleanup() */
567     le_init();
568     return;
569 }
570
571 int
572 le_inbuf() {
573     int rc = 0;
574     if (le_start != le_end) {
575         rc = (le_end -
576               le_start +
577               LEBUFSIZ) % LEBUFSIZ;
578     }
579     return(rc);
580 }
581
582 int
583 #ifdef CK_ANSIC
584 le_putchar(CHAR ch)
585 #else
586 le_putchar(ch) CHAR ch;
587 #endif /* CK_ANSIC */
588 /* le_putchar */ {
589     if ((le_start - le_end + LEBUFSIZ)%LEBUFSIZ == 1) {
590         debug(F110,"le_putchar","buffer is full",0);
591         return(-1);
592     }
593     le_buf[le_end++] = ch;
594     if (le_end == LEBUFSIZ)
595       le_end = 0;
596     le_data = 1;
597     return(0);
598 }
599
600 int
601 #ifdef CK_ANSIC
602 le_puts(CHAR * s, int n)
603 #else
604 le_puts(s,n) CHAR * s; int n;
605 #endif /* CK_ANSIC */
606 /* le_puts */ {
607     int rc = 0;
608     int i = 0;
609     CHAR * p = (CHAR *)"le_puts";
610     ckhexdump(p,s,n);
611     for (i = 0; i < n; i++)
612       rc = le_putchar((char)s[i]);
613     debug(F101,"le_puts","",rc);
614     return(rc);
615 }
616
617 int
618 #ifdef CK_ANSIC
619 le_putstr(CHAR * s)
620 #else
621 le_putstr(s) CHAR * s;
622 #endif /* CK_ANSIC */
623 /* le_puts */ {
624     CHAR * p;
625     int rc = 0;
626     p = (CHAR *)"le_putstr";
627     ckhexdump(p,s,(int)strlen((char *)s));
628     for (p = s; *p && !rc; p++)
629       rc = le_putchar(*p);
630     return(rc);
631 }
632
633 int
634 #ifdef CK_ANSIC
635 le_getchar(CHAR * pch)
636 #else /* CK_ANSIC */
637 le_getchar(pch) CHAR * pch;
638 #endif /* CK_ANSIC */
639 /* le_gatchar */ {
640     int rc = 0;
641     if (le_start != le_end) {
642         *pch = le_buf[le_start];
643         le_buf[le_start] = 0;
644         le_start++;
645
646         if (le_start == LEBUFSIZ)
647           le_start = 0;
648
649         if (le_start == le_end) {
650             le_data = 0;
651         }
652         rc++;
653     } else {
654         *pch = 0;
655     }
656     return(rc);
657 }
658 #endif /* NETLEBUF */
659
660 #ifdef VMS
661 /*
662   In edit 190, we moved tn_ini() to be called from within netopen().
663   But tn_ini() calls ttol(), and ttol() checks to see if it's a net
664   connection, but the flag for that isn't set until after netopen()
665   is finished.  Since, in this module, we are always doing network
666   output anyway, we just call nettol() directly, instead of going thru
667   ttol().  Only needed for VMS, since UNIX, AOS/VS, and VOS can handle
668   net connections just like regular connections in ttol(), and OS/2
669   has a special routine for this.
670 */
671 #define ttol nettol
672 #endif /* VMS */
673
674 int tcpsrfd = -1;
675
676 #ifdef CK_KERBEROS
677
678 char * krb5_d_principal = NULL;         /* Default principal */
679 char * krb5_d_instance = NULL;          /* Default instance */
680 char * krb5_d_realm = NULL;             /* Default realm */
681 char * krb5_d_cc = NULL;                /* Default credentials cache */
682 char * krb5_d_srv   = NULL;             /* Default Service */
683 int    krb5_d_lifetime = 600;           /* Default lifetime (10 hours) */
684 int    krb5_d_forwardable = 0;          /* creds not forwardable */
685 int    krb5_d_proxiable = 0;            /* creds not proxiable */
686 int    krb5_d_renewable = 0;            /* creds not renewable (0 min) */
687 int    krb5_autoget = 1;                /* Autoget TGTs */
688 int    krb5_autodel = 0;                /* Auto delete TGTs */
689 int    krb5_d_getk4 = 0;                /* K5 Kinit gets K4 TGTs */
690 int    krb5_checkaddrs = 1;             /* Check TGT Addrs */
691 int    krb5_d_no_addresses = 0;         /* Do not include IP Addresses */
692 char * krb5_d_addrs[KRB5_NUM_OF_ADDRS+1]={NULL,NULL}; /* Addrs to include */
693 int    krb5_errno = 0;                  /* Last K5 errno */
694 char * krb5_errmsg = NULL;              /* Last K5 errmsg */
695 char * k5_keytab = NULL;
696
697 char * krb4_d_principal = NULL;         /* Default principal */
698 char * krb4_d_realm = NULL;             /* Default realm */
699 char * krb4_d_srv   = NULL;             /* Default Service */
700 int    krb4_d_lifetime = 600;           /* Default lifetime (10 hours) */
701 int    krb4_d_preauth = 1;              /* Use preauth requests */
702 char * krb4_d_instance = NULL;          /* Default instance */
703 int    krb4_autoget = 1;                /* Autoget TGTs */
704 int    krb4_autodel = 0;                /* Auto delete TGTs */
705 int    krb4_checkaddrs = 1;             /* Check TGT Addrs */
706 char * k4_keytab = NULL;
707
708 int    krb4_errno = 0;                  /* Last K4 errno */
709 char * krb4_errmsg = NULL;              /* Last K4 errmsg */
710
711 struct krb_op_data krb_op = {           /* Operational data structure */
712     0, NULL                             /* (version, cachefile) */
713 };
714
715 struct krb4_init_data krb4_init = {     /* Kerberos 4 INIT data structure */
716     0, NULL, NULL, NULL, NULL
717 };
718
719 struct krb5_init_data krb5_init = {     /* Kerberos 5 INIT data structure */
720     0, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, 0, 0, 0,
721     { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
722       NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
723     0
724 };
725
726 struct krb5_list_cred_data krb5_lc = {  /* List Credentials data structure */
727     0, 0, 0
728 };
729
730 int krb_action = -1;                    /* Kerberos action to perform */
731
732 #ifndef CK_AUTHENTICATION
733 char *
734 ck_krb4_getrealm() {
735     return("");
736 }
737 char *
738 ck_krb5_getrealm(cc) char * cc; {
739     return("");
740 }
741 char *
742 ck_krb4_getprincipal() {
743     return("");
744 }
745 char *
746 ck_krb5_getprincipal(cc) char * cc; {
747     return("");
748 }
749 #endif /* CK_AUTHENTICATION */
750
751 /*  I N I _ K E R B  --  Initialize Kerberos data  */
752
753 VOID
754 ini_kerb() {
755     int i;
756
757     krb_action = -1;                    /* No action specified */
758
759     krb_op.version = 0;                 /* Kerberos version (none) */
760     krb_op.cache = NULL;                /* Cache file (none) */
761
762 /* Kerberos 5 */
763
764     krb5_init.forwardable = krb5_d_forwardable; /* Init switch values... */
765     krb5_init.proxiable   = krb5_d_proxiable;
766     krb5_init.lifetime    = krb5_d_lifetime;
767     krb5_init.renew       = 0;
768     krb5_init.renewable   = krb5_d_renewable;
769     krb5_init.validate    = 0;
770     krb5_init.no_addresses = krb5_d_no_addresses;
771     krb5_init.getk4       = krb5_d_getk4;
772     if (krb5_init.postdate) {
773         free(krb5_init.postdate);
774         krb5_init.postdate = NULL;
775     }
776     if (krb5_init.service) {
777         free(krb5_init.service);
778         krb5_init.service = NULL;
779     }
780     if (!krb5_d_cc || !krb5_d_cc[0]) {  /* Set default cache */
781         char * p;
782         p = ck_krb5_get_cc_name();
783         makestr(&krb5_d_cc,(p && p[0]) ? p : NULL);
784     }
785     if (!krb5_d_realm || !krb5_d_realm[0]) { /* Set default realm */
786         char * p;
787         p = ck_krb5_getrealm(krb5_d_cc);
788         makestr(&krb5_d_realm,(p && p[0]) ? p : NULL);
789     }
790     makestr(&krb5_init.instance,krb5_d_instance);
791     makestr(&krb5_init.realm,krb5_d_realm); /* Set realm from default */
792     if (krb5_init.password) {
793         memset(krb5_init.password,0xFF,strlen(krb5_init.password));
794         free(krb5_init.password);
795         krb5_init.password = NULL;
796     }
797     if (!krb5_d_principal) {            /* Default principal */
798         /* a Null principal indicates the user should be prompted */
799         char * p = ck_krb5_getprincipal(krb5_d_cc);
800         if (!p || !(*p))
801           p = (char *)uidbuf;           /* Principal = user */
802                 makestr(&krb5_d_principal,(p && p[0]) ? p : NULL);
803     }
804     makestr(&krb5_init.principal,krb5_d_principal);
805     for (i = 0; i <= KRB5_NUM_OF_ADDRS; i++) {
806         if (krb5_init.addrs[i])
807           free(krb5_init.addrs[i]);
808         krb5_init.addrs[i] = NULL;
809     }
810     for (i = 0; i <= KRB5_NUM_OF_ADDRS && krb5_d_addrs[i]; i++) {
811         makestr(&krb5_init.addrs[i],krb5_d_addrs[i]);
812     }
813
814     /* Kerberos 4 */
815
816     krb4_init.lifetime = krb4_d_lifetime;
817     krb4_init.preauth  = krb4_d_preauth;
818     makestr(&krb4_init.instance,krb4_d_instance);
819     if (!krb4_d_realm || !krb4_d_realm[0]) {/* Set default realm */
820         char * p;
821         p = ck_krb4_getrealm();
822                 makestr(&krb4_d_realm,(p && p[0]) ? p : NULL);
823     }
824     makestr(&krb4_init.realm,krb4_d_realm);
825     if (krb4_init.password) {
826         memset(krb4_init.password,0xFF,strlen(krb4_init.password));
827         free(krb4_init.password);
828         krb4_init.password = NULL;
829     }
830     if (!krb4_d_principal) {            /* Default principal */
831         /* a Null principal indicates the user should be prompted */
832         char * p = ck_krb4_getprincipal();
833         if (!p || !(*p))
834           p = (char *)uidbuf;           /* Principal = user */
835         makestr(&(krb4_d_principal),(p && p[0]) ? p : NULL);
836     }
837     makestr(&(krb4_init.principal),krb4_d_principal);
838 }
839
840 /*  D O A U T H  --  AUTHENTICATE action routine  */
841
842 int
843 doauth(cx) int cx; {                    /* AUTHENTICATE action routine */
844     int rc = 0;                         /* Return code */
845
846 #ifdef CK_AUTHENTICATION
847 #ifdef OS2
848     if (!ck_security_loaddll())         /* Load various DLLs */
849       return(rc);
850 #endif /* OS2 */
851     if (krb_op.version == 4) {          /* Version = 4 */
852 #ifdef COMMENT
853         sho_auth(AUTHTYPE_KERBEROS_V4);
854 #endif /* COMMENT */
855         if (!ck_krb4_is_installed()) {
856             printf("?Kerberos 4 is not installed\n");
857             return(0);
858         }
859         switch (krb_action) {           /* Perform V4 functions */
860           case KRB_A_IN:                /* INIT */
861             rc |= !(ck_krb4_initTGT(&krb_op,&krb4_init) < 0);
862             break;
863           case KRB_A_DE:                /* DESTROY */
864             rc |= !(ck_krb4_destroy(&krb_op) < 0);
865             break;
866           case KRB_A_LC:                /* LIST-CREDENTIALS */
867             rc |= !(ck_krb4_list_creds(&krb_op) < 0);
868             break;
869         }
870     }
871     if (krb_op.version == 5) {          /* V5 functions */
872 #ifdef COMMENT
873         sho_auth(AUTHTYPE_KERBEROS_V5);
874 #endif /* COMMENT */
875         if (!ck_krb5_is_installed()) {
876             printf("?Kerberos 5 is not installed\n");
877             return(0);
878         }
879         switch (krb_action) {
880           case KRB_A_IN:                /* INIT */
881             rc |= !(ck_krb5_initTGT(&krb_op,&krb5_init,
882                                      krb5_init.getk4 ? &krb4_init : 0) < 0);
883             break;
884           case KRB_A_DE:                /* DESTROY */
885             rc |= !(ck_krb5_destroy(&krb_op) < 0);
886             break;
887           case KRB_A_LC:                /* LIST-CREDENTIALS */
888             if (krb_op.version == 0)
889               printf("\n");
890             rc |= !(ck_krb5_list_creds(&krb_op,&krb5_lc) < 0);
891             break;
892         }
893     }
894 #else
895 #ifndef NOICP
896 #ifndef NOSHOW
897     rc = sho_auth(0);                   /* Show all */
898 #endif /* NOSHOW */
899 #endif /* NOICP */
900 #endif /* CK_AUTHENTICATION */
901     return(rc);
902 }
903 #endif /* CK_KERBEROS */
904
905 #ifdef TCPSOCKET
906 #ifndef OS2
907 #ifndef NOLISTEN                        /* For incoming connections */
908
909 #ifndef INADDR_ANY
910 #define INADDR_ANY 0
911 #endif /* INADDR_ANY */
912
913 _PROTOTYP( int ttbufr, ( VOID ) );
914 _PROTOTYP( int tcpsrv_open, (char *, int *, int, int ) );
915
916 static unsigned short tcpsrv_port = 0;
917
918 #endif /* NOLISTEN */
919 #endif /* OS2 */
920
921 static char svcbuf[80];                 /* TCP service string */
922 static int svcnum = 0;                  /* TCP port number */
923
924 #endif /* TCPSOCKET */
925
926 /*
927   TCPIPLIB means use separate socket calls for i/o, while on UNIX the
928   normal file system calls are used for TCP/IP sockets too.
929   Means "DEC_TCPIP or MULTINET or WINTCP or OS2 or BEBOX" (see ckcnet.h),
930 */
931
932 #ifdef TCPIPLIB
933
934 /* For buffered network reads... */
935 /*
936   If the buffering code is written right, it shouldn't matter
937   how long this buffer is.
938 */
939 #ifdef OS2
940 #ifdef NT
941 #define TTIBUFL 64240                   /* 44 * 1460 (MSS) */
942 #else
943 #define TTIBUFL 32120                   /* 22 * 1460 (MSS) */
944 #endif /* NT */
945 #else /* OS2 */
946 #define TTIBUFL 8191                    /* Let's use 8K. */
947 #endif /* OS2 */
948
949 CHAR ttibuf[TTIBUFL+1];
950
951 /*
952   select() is used in preference to alarm()/signal(), but different systems
953   use different forms of select()...
954 */
955 #ifndef NOSELECT         /* Option to override BSDSELECT */
956 #ifdef BELLV10
957 /*
958   Note: Although BELLV10 does have TCP/IP support, and does use the unique
959   form of select() that is evident in this module (and in ckutio.c), it does
960   not have a sockets library and so we can't build Kermit TCP/IP support for
961   it.  For this, somebody would have to write TCP/IP streams code.
962 */
963 #define BELLSELECT
964 #ifndef FD_SETSIZE
965 #define FD_SETSIZE 128
966 #endif /* FD_SETSIZE */
967 #else
968 #ifdef WINTCP                           /* VMS with Wollongong WIN/TCP */
969 #ifndef OLD_TWG                         /* TWG 3.2 has only select(read) */
970 #define BSDSELECT
971 #endif /* OLD_TWG */
972 #else
973 #ifdef CMU_TCPIP                        /* LIBCMU can do select */
974 #define BSDSELECT
975 #else
976 #ifdef DEC_TCPIP
977 #define BSDSELECT
978 #else
979 #ifdef OS2                              /* OS/2 with TCP/IP */
980 #ifdef NT
981 #define BSDSELECT
982 #else /* NT */
983 #define IBMSELECT
984 #endif /* NT */
985 #endif /* OS2 */
986 #endif /* DEC_TCPIP */
987 #endif /* CMU_TCPIP */
988 #endif /* WINTCP */
989 #endif /* BELLV10 */
990 #endif /* NOSELECT */
991 /*
992   Others (TGV, TCPware, ...) use alarm()/signal().  The BSDSELECT case does not
993   compile at all; the IBMSELECT case compiles and links but crashes at runtime.
994   NOTE: If any of these can be converted to select(), they should be for two
995   reasons: (1) It's a lot faster; (2) certain sockets libraries do not like
996   their socket_read() calls to be interrupted; subsequent socket_read()'s tend
997   to fail with EBUSY.  This happened in the UCX case before it was converted
998   to use select().
999 */
1000 #ifndef OS2
1001 #ifndef VMS
1002 static                                  /* These are used in CKVTIO.C */
1003 #endif /* VMS */                        /* And in CKONET.C            */
1004 #endif /* OS2 */
1005 int
1006   ttibp = 0,
1007   ttibn = 0;
1008 /*
1009   Read bytes from network into internal buffer ttibuf[].
1010   To be called when input buffer is empty, i.e. when ttibn == 0.
1011
1012   Other network reading routines, like ttinc, ttinl, ttxin, should check the
1013   internal buffer first, and call this routine for a refill if necessary.
1014
1015   Returns -1 on error, 0 if nothing happens.  When data is read successfully,
1016   returns number of bytes read, and sets global ttibn to that number and
1017   ttibp (the buffer pointer) to zero.
1018 */
1019 _PROTOTYP( int ttbufr, ( VOID ) );
1020 int
1021 ttbufr() {                              /* TT Buffer Read */
1022     int count;
1023
1024     if (ttnet != NET_TCPB)              /* First make sure current net is */
1025       return(-1);                       /* TCP/IP; if not, do nothing. */
1026
1027 #ifdef OS2
1028     RequestTCPIPMutex(SEM_INDEFINITE_WAIT);
1029 #endif /* OS2 */
1030
1031     if (ttibn > 0) {                    /* Our internal buffer is not empty, */
1032 #ifdef OS2
1033         ReleaseTCPIPMutex();
1034 #endif /* OS2 */
1035         return(ttibn);                  /* so keep using it. */
1036     }
1037
1038     if (ttyfd == -1) {                  /* No connection, error */
1039 #ifdef OS2
1040         ReleaseTCPIPMutex();
1041 #endif /* OS2 */
1042         return(-2);
1043     }
1044
1045     ttibp = 0;                          /* Else reset pointer to beginning */
1046
1047 #ifdef WINTCP
1048     count = 512;                        /* This works for WIN/TCP */
1049 #else
1050 #ifdef DEC_TCPIP
1051     count = 512;                        /* UCX */
1052 #else
1053 #ifdef OS2
1054     count = TTIBUFL;
1055 #else                                   /* Multinet, etc. */
1056     count = ttchk();                    /* Check network input buffer, */
1057     if (ttibn > 0) {                    /* which can put a char there! */
1058         debug(F111,"ttbufr","ttchk() returns",count);
1059 #ifdef OS2
1060         ReleaseTCPIPMutex();
1061 #endif /* OS2 */
1062         return(ttibn);
1063     }
1064     if (count < 0) {                     /* Read error - connection closed */
1065 #ifdef OS2
1066         ReleaseTCPIPMutex();
1067 #endif /* OS2 */
1068         return(-2);
1069     }
1070     else if (count > TTIBUFL)           /* Too many to read */
1071       count = TTIBUFL;
1072     else if (count == 0)                /* None, so force blocking read */
1073       count = 1;
1074 #endif /* OS2 */
1075 #endif /* DEC_TCPIP */
1076 #endif /* WINTCP */
1077     debug(F101,"ttbufr count 1","",count);
1078
1079 #ifdef CK_SSL
1080     if (ssl_active_flag || tls_active_flag) {
1081         int error;
1082       ssl_read:
1083         if (ssl_active_flag)
1084           count = SSL_read(ssl_con, ttibuf, count);
1085         else
1086           count = SSL_read(tls_con, ttibuf, count);
1087         error = SSL_get_error(ssl_active_flag?ssl_con:tls_con,count);
1088         switch (error) {
1089           case SSL_ERROR_NONE:
1090             debug(F111,"ttbufr SSL_ERROR_NONE","count",count);
1091             if (count > 0) {
1092                 ttibp = 0;              /* Reset buffer pointer. */
1093                 ttibn = count;
1094 #ifdef OS2
1095                 ReleaseTCPIPMutex();
1096 #endif /* OS2 */
1097                 return(ttibn);          /* Return buffer count. */
1098             } else if (count < 0) {
1099 #ifdef OS2
1100                 ReleaseTCPIPMutex();
1101 #endif /* OS2 */
1102                 return(-1);
1103             } else {
1104                 netclos();
1105 #ifdef OS2
1106                 ReleaseTCPIPMutex();
1107 #endif /* OS2 */
1108                 return(-2);
1109             }
1110           case SSL_ERROR_WANT_WRITE:
1111             debug(F100,"ttbufr SSL_ERROR_WANT_WRITE","",0);
1112 #ifdef OS2
1113               ReleaseTCPIPMutex();
1114 #endif /* OS2 */
1115             return(-1);
1116           case SSL_ERROR_WANT_READ:
1117             debug(F100,"ttbufr SSL_ERROR_WANT_READ","",0);
1118 #ifdef OS2
1119             ReleaseTCPIPMutex();
1120 #endif /* OS2 */
1121             return(-1);
1122           case SSL_ERROR_SYSCALL:
1123               if ( count == 0 ) { /* EOF */
1124                   netclos();
1125 #ifdef OS2
1126                   ReleaseTCPIPMutex();
1127 #endif /* OS2 */
1128                   return(-2);
1129               } else {
1130                   int rc = -1;
1131 #ifdef NT
1132                   int gle = GetLastError();
1133                   debug(F111,"ttbufr SSL_ERROR_SYSCALL",
1134                          "GetLastError()",gle);
1135                   rc = os2socketerror(gle);
1136                   if (rc == -1)
1137                       rc = -2;
1138                   else if ( rc == -2 )
1139                       rc = -1;
1140 #endif /* NT */
1141 #ifdef OS2
1142                   ReleaseTCPIPMutex();
1143 #endif /* OS2 */
1144                   return(rc);
1145               }
1146           case SSL_ERROR_WANT_X509_LOOKUP:
1147             debug(F100,"ttbufr SSL_ERROR_WANT_X509_LOOKUP","",0);
1148             netclos();
1149 #ifdef OS2
1150               ReleaseTCPIPMutex();
1151 #endif /* OS2 */
1152             return(-2);
1153           case SSL_ERROR_SSL:
1154               if (bio_err!=NULL) {
1155                   int len;
1156                   extern char ssl_err[];
1157                   BIO_printf(bio_err,"ttbufr SSL_ERROR_SSL\n");
1158                   ERR_print_errors(bio_err);
1159                   len = BIO_read(bio_err,ssl_err,SSL_ERR_BFSZ);
1160                   ssl_err[len < SSL_ERR_BFSZ ? len : SSL_ERR_BFSZ] = '\0';
1161                   debug(F110,"ttbufr SSL_ERROR_SSL",ssl_err,0);
1162                   if (ssl_debug_flag)                  
1163                       printf(ssl_err);
1164               } else if (ssl_debug_flag) {
1165                   debug(F100,"ttbufr SSL_ERROR_SSL","",0);
1166                   fflush(stderr);
1167                   fprintf(stderr,"ttbufr SSL_ERROR_SSL\n");
1168                   ERR_print_errors_fp(stderr);
1169               }
1170 #ifdef COMMENT
1171               netclos();
1172 #endif /* COMMENT */
1173 #ifdef OS2
1174               ReleaseTCPIPMutex();
1175 #endif /* OS2 */
1176             return(-2);
1177           case SSL_ERROR_ZERO_RETURN:
1178             debug(F100,"ttbufr SSL_ERROR_ZERO_RETURN","",0);
1179             netclos();
1180 #ifdef OS2
1181               ReleaseTCPIPMutex();
1182 #endif /* OS2 */
1183             return(-2);
1184           default:
1185               debug(F100,"ttbufr SSL_ERROR_?????","",0);
1186               netclos();
1187 #ifdef OS2
1188               ReleaseTCPIPMutex();
1189 #endif /* OS2 */
1190               return(-2);
1191           }
1192     }
1193 #endif /* CK_SSL */
1194
1195 #ifdef COMMENT
1196 /*
1197  This is for nonblocking reads, which we don't do any more.  This code didn't
1198  work anyway, in the sense that a broken connection was never sensed.
1199 */
1200     if ((count = socket_read(ttyfd,&ttibuf[ttibp+ttibn],count)) < 1) {
1201         if (count == -1 && socket_errno == EWOULDBLOCK) {
1202             debug(F100,"ttbufr finds nothing","",0);
1203 #ifdef OS2
1204             ReleaseTCPIPMutex();
1205 #endif /* OS2 */
1206             return(0);
1207         } else {
1208             debug(F101,"ttbufr socket_read error","",socket_errno);
1209 #ifdef OS2
1210             ReleaseTCPIPMutex();
1211 #endif /* OS2 */
1212             return(-1);
1213         }
1214
1215     } else if (count == 0) {
1216         debug(F100,"ttbufr socket eof","",0);
1217 #ifdef OS2
1218         ReleaseTCPIPMutex();
1219 #endif /* OS2 */
1220         return(-1);
1221     }
1222 #else /* COMMENT */
1223
1224 /* This is for blocking reads */
1225
1226 #ifndef VMS
1227 #ifdef SO_OOBINLINE
1228     {
1229         int outofband = 0;
1230 #ifdef BELLSELECT
1231         if (select(128, NULL, NULL, efds, 0) > 0 && FD_ISSET(ttyfd, efds))
1232           outofband = 1;
1233 #else
1234 #ifdef BSDSELECT
1235         fd_set efds;
1236         struct timeval tv;
1237         FD_ZERO(&efds);
1238         FD_SET(ttyfd, &efds);
1239         tv.tv_sec  = tv.tv_usec = 0L;
1240         debug(F100,"Out-of-Band BSDSELECT","",0);
1241 #ifdef NT
1242         WSASafeToCancel = 1;
1243 #endif /* NT */
1244         if (select(FD_SETSIZE, NULL, NULL, &efds, &tv) > 0 &&
1245             FD_ISSET(ttyfd, &efds))
1246           outofband = 1;
1247 #ifdef NT
1248         WSASafeToCancel = 0;
1249 #endif /* NT */
1250 #else /* !BSDSELECT */
1251 #ifdef IBMSELECT
1252 /* Is used by OS/2 ... */
1253 /* ... and it came in handy!  For our TCP/IP layer, it avoids all the fd_set */
1254 /* and timeval stuff since this is the only place where it is used. */
1255         int socket = ttyfd;
1256         debug(F100,"Out-of-Band IBMSELECT","",0);
1257         if ((select(&socket, 0, 0, 1, 0L) == 1) && (socket == ttyfd))
1258           outofband = 1;
1259 #else /* !IBMSELECT */
1260 /*
1261   If we can't use select(), then we use the regular alarm()/signal()
1262   timeout mechanism.
1263 */
1264       debug(F101,"Out-of-Band data not supported","",0);
1265       outofband = 0;
1266
1267 #endif /* IBMSELECT */
1268 #endif /* BSDSELECT */
1269 #endif /* BELLSELECT */
1270       if (outofband) {
1271          /* Get the Urgent Data */
1272          /* if OOBINLINE is disabled this should be only a single byte      */
1273          /* MS Winsock has a bug in Windows 95.  Extra bytes are delivered  */
1274          /* That were never sent.                                           */
1275 #ifdef OS2
1276           RequestTCPIPMutex(SEM_INDEFINITE_WAIT);
1277 #endif /* OS2 */
1278           count = socket_recv(ttyfd,&ttibuf[ttibp+ttibn],count,MSG_OOB);
1279 #ifdef OS2
1280           ReleaseTCPIPMutex();
1281 #endif /* OS2 */
1282           if (count <= 0) {
1283               int s_errno = socket_errno;
1284               debug(F101, "ttbufr socket_recv MSG_OOB","",count);
1285               debug(F101, "ttbufr socket_errno","",s_errno);
1286 #ifdef OS2ONLY
1287               if (count < 0 && (s_errno == 0 || s_errno == 23)) {
1288                   /* These appear in OS/2 - don't know why   */
1289                   /* ignore it and read as normal data       */
1290                   /* and break, then we will attempt to read */
1291                   /* the port using normal read() techniques */
1292                   debug(F100,"ttbufr handing as in-band data","",0);
1293                   count = 1;
1294               } else {
1295                   netclos();                    /* *** *** */
1296 #ifdef OS2
1297                   ReleaseTCPIPMutex();
1298 #endif /* OS2 */
1299                   return(-2);
1300               }
1301 #else /* OS2ONLY */
1302               netclos();                        /* *** *** */
1303 #ifdef OS2
1304               ReleaseTCPIPMutex();
1305 #endif /* OS2 */
1306               return(-2);
1307 #endif /* OS2ONLY */
1308           } else {                      /* we got out-of-band data */
1309               ckhexdump("ttbufr out-of-band chars",&ttibuf[ttibp+ttibn],count);
1310 #ifdef BETADEBUG
1311               bleep(BP_NOTE);
1312 #endif /* BETADEBUG */
1313 #ifdef RLOGCODE                         /* blah */
1314               if (ttnproto == NP_RLOGIN  ||
1315                   ttnproto == NP_K4LOGIN || ttnproto == NP_EK4LOGIN ||
1316                   ((ttnproto == NP_K5LOGIN || ttnproto == NP_EK5LOGIN) && 
1317                   !rlog_inband)
1318                    )
1319               {
1320                   /*
1321                     When urgent data is read with MSG_OOB and not OOBINLINE
1322                     then urgent data and normal data are not mixed.  So
1323                     treat the entire buffer as urgent data.
1324                   */
1325                   rlog_oob(&ttibuf[ttibp+ttibn], count);
1326 #ifdef OS2
1327                   ReleaseTCPIPMutex();
1328 #endif /* OS2 */
1329                   return ttbufr();
1330               } else
1331 #endif /* RLOGCODE */ /* blah */
1332 #ifdef COMMENT
1333             /*
1334                I haven't written this yet, nor do I know what it should do
1335              */
1336                 if (ttnproto == NP_TELNET) {
1337                     tn_oob();
1338 #ifdef OS2
1339                     ReleaseTCPIPMutex();
1340 #endif /* OS2 */
1341                     return 0;
1342               } else
1343 #endif /* COMMENT */
1344               {
1345                   /* For any protocols we don't have a special out-of-band  */
1346                   /* handler for, just put the bytes in the normal buffer   */
1347                   /* and return                                             */
1348
1349                   ttibp += 0;       /* Reset buffer pointer. */
1350                   ttibn += count;
1351 #ifdef DEBUG
1352                   /* Got some bytes. */
1353                   debug(F101,"ttbufr count 2","",count);
1354                   if (count > 0)
1355                       ttibuf[ttibp+ttibn] = '\0';
1356                   debug(F111,"ttbufr ttibuf",ttibuf,ttibp);
1357 #endif /* DEBUG */
1358 #ifdef OS2
1359                   ReleaseTCPIPMutex();
1360 #endif /* OS2 */
1361                   return(ttibn);    /* Return buffer count. */
1362               }
1363           }
1364       }
1365     }
1366 #endif /* SO_OOBINLINE */
1367 #endif /* VMS */
1368
1369     count = socket_read(ttyfd,&ttibuf[ttibp+ttibn],count);
1370     if (count <= 0) {
1371         int s_errno = socket_errno;
1372         debug(F101,"ttbufr socket_read","",count);
1373         debug(F101,"ttbufr socket_errno","",s_errno);
1374 #ifdef OS2
1375         if (count == 0 || os2socketerror(s_errno) < 0) {
1376             netclos();
1377             ReleaseTCPIPMutex();
1378             return(-2);
1379         }
1380         ReleaseTCPIPMutex();
1381         return(-1);
1382 #else /* OS2 */
1383         netclos();                      /* *** *** */
1384         return(-2);
1385 #endif /* OS2 */
1386     }
1387 #endif /* COMMENT */ /* (blocking vs nonblock reads...) */
1388     else {
1389         ttibp = 0;                      /* Reset buffer pointer. */
1390         ttibn += count;
1391 #ifdef DEBUG
1392         debug(F101,"ttbufr count 2","",count); /* Got some bytes. */
1393         if (count > 0)
1394           ttibuf[ttibp+ttibn] = '\0';
1395         debug(F111,"ttbufr ttibuf",&ttibuf[ttibp],ttibn);
1396 #endif /* DEBUG */
1397
1398 #ifdef OS2
1399         ReleaseTCPIPMutex();
1400 #endif /* OS2 */
1401         return(ttibn);                  /* Return buffer count. */
1402     }
1403 }
1404 #endif /* TCPIPLIB */
1405
1406 #ifndef IBMSELECT
1407 #ifndef BELLSELECT
1408 #ifndef BSDSELECT               /* Non-TCPIPLIB case */
1409 #ifdef SELECT
1410 #define BSDSELECT
1411 #endif /* SELECT */
1412 #endif /* BSDSELECT */
1413 #endif /* BELLSELECT */
1414 #endif /* IBMSELECT */
1415
1416 #define TELNET_PORT 23          /* Should do lookup, but it won't change */
1417 #define RLOGIN_PORT 513
1418 #define KERMIT_PORT 1649
1419 #define KLOGIN_PORT 543
1420 #define EKLOGIN_PORT 2105
1421
1422 #ifndef NONET
1423 /*
1424   C-Kermit network open/close functions for BSD-sockets.
1425   Much of this code shared by SunLink X.25, which also uses the socket library.
1426 */
1427
1428 /*  N E T O P N  --  Open a network connection.  */
1429 /*
1430   Call with:
1431     name of host (or host:service),
1432     lcl - local-mode flag to be set if this function succeeds,
1433     network type - value defined in ckunet.h.
1434 */
1435 #ifdef TCPSOCKET
1436 struct hostent *
1437 #ifdef CK_ANSIC
1438 ck_copyhostent(struct hostent * h)
1439 #else /* CK_ANSIC */
1440 ck_copyhostent(h) struct hostent * h;
1441 #endif /* CK_ANSIC */
1442 {
1443     /*
1444      *  The hostent structure is dynamic in nature.
1445      *  struct  hostent {
1446      *  char    * h_name;
1447      *  char    * * h_aliases;
1448      *  short   h_addrtype;
1449      *  short   h_length;
1450      *  char    * * h_addr_list;
1451      *  #define h_addr  h_addr_list[0]
1452      */
1453 #define HOSTENTCNT 5
1454     static struct hostent hosts[HOSTENTCNT] = {{NULL,NULL,0,0,NULL},
1455                                                {NULL,NULL,0,0,NULL},
1456                                                {NULL,NULL,0,0,NULL},
1457                                                {NULL,NULL,0,0,NULL},
1458                                                {NULL,NULL,0,0,NULL}};
1459     static int    next = 0;
1460     int    i,cnt;
1461     char ** pp;
1462
1463     if ( h == NULL )
1464         return(NULL);
1465
1466     if (next == HOSTENTCNT)
1467         next = 0;
1468
1469     if ( hosts[next].h_name ) {
1470         free(hosts[next].h_name);
1471         hosts[next].h_name = NULL;
1472     }
1473     if ( hosts[next].h_aliases ) {
1474         pp = hosts[next].h_aliases;
1475         while ( *pp ) {
1476             free(*pp);
1477             pp++;
1478         }
1479         free(hosts[next].h_aliases);
1480     }
1481 #ifdef HADDRLIST
1482     if ( hosts[next].h_addr_list ) {
1483         pp = hosts[next].h_addr_list;
1484         while ( *pp ) {
1485             free(*pp);
1486             pp++;
1487         }
1488         free(hosts[next].h_addr_list);
1489     }
1490 #endif /* HADDRLIST */
1491
1492     makestr(&hosts[next].h_name,h->h_name);
1493     if (h->h_aliases) {
1494         for ( cnt=0,pp=h->h_aliases; pp && *pp; pp++,cnt++) ;
1495         /* The following can give warnings in non-ANSI builds */
1496         hosts[next].h_aliases = (char **) malloc(sizeof(char *) * (cnt+1));
1497         for ( i=0; i<cnt; i++) {
1498             hosts[next].h_aliases[i] = NULL;
1499             makestr(&hosts[next].h_aliases[i],h->h_aliases[i]);
1500         }
1501         hosts[next].h_aliases[i] = NULL;
1502     } else
1503         hosts[next].h_aliases = NULL;
1504
1505     hosts[next].h_addrtype = h->h_addrtype;
1506     hosts[next].h_length = h->h_length;
1507
1508 #ifdef HADDRLIST
1509 #ifdef h_addr
1510     if (h->h_addr_list) {
1511         for ( cnt=0,pp=h->h_addr_list; pp && *pp; pp++,cnt++) ;
1512         /* The following can give warnings non-ANSI builds */
1513         hosts[next].h_addr_list = (char **) malloc(sizeof(char *) * (cnt+1));
1514         for ( i=0; i<cnt; i++) {
1515             hosts[next].h_addr_list[i] = malloc(h->h_length);
1516             bcopy(h->h_addr_list[i],hosts[next].h_addr_list[i],h->h_length);
1517         }
1518         hosts[next].h_addr_list[i] = NULL;
1519     } else
1520         hosts[next].h_addr_list = NULL;
1521 #else
1522     bcopy(h->h_addr, &hosts[next].h_addr, h->h_length);
1523 #endif /* h_addr */
1524 #else /* HADDRLIST */
1525     bcopy(h->h_addr, &hosts[next].h_addr, h->h_length);
1526 #endif /* HADDRLIST */
1527
1528     return(&hosts[next++]);
1529 }
1530
1531 #ifdef EXCELAN
1532 /*
1533   Most other BSD sockets implementations define these in header files
1534   and libraries.
1535 */
1536 struct servent {
1537     unsigned short s_port;
1538 };
1539
1540 struct hostent {
1541     short h_addrtype;
1542     struct in_addr h_addr;
1543     int h_length;
1544 };
1545
1546 struct servent *
1547 getservbyname(service, connection) char *service,*connection; {
1548     static struct servent servrec;
1549     int port;
1550
1551     port = 0;
1552     if (strcmp(service, "telnet") == 0) port = 23;
1553     else if (strcmp(service, "smtp") == 0) port = 25;
1554     else port = atoi(service);
1555
1556     debug(F101,"getservbyname return port ","",port);
1557
1558     if (port > 0) {
1559         servrec.s_port = htons(port);
1560         return(&servrec);
1561     }
1562     return((struct servent *) NULL);
1563 }
1564
1565 struct hostent *
1566 gethostbyname(hostname) char *hostname; {
1567     return((struct hostent *) NULL);
1568 }
1569
1570 unsigned long
1571 inet_addr(name) char *name; {
1572     unsigned long addr;
1573
1574     addr = rhost(&name);
1575     debug(F111,"inet_addr ",name,(int)addr);
1576     return(addr);
1577 }
1578
1579 char *
1580 inet_ntoa(in) struct in_addr in; {
1581     static char name[80];
1582     ckmakxmsg(name, ckuitoa(in.s_net),".",ckuitoa(in.s_host),".",
1583                ckuitoa(in.s_lh),".", ckuitoa(in.s_impno));
1584     return(name);
1585 }
1586 #else
1587 #ifdef DEC_TCPIP                        /* UCX */
1588
1589 int ucx_port_bug = 0;                   /* Explained below */
1590
1591 #ifdef OLDIP                            /* Very old VAXC or GCC */
1592 /*
1593   Note that my oldest VAX C (V3.1-051) does not need (or want) OLDIP,
1594   hence the "Very old" in the comment - SMS, 2010/03/15.
1595 */
1596 #define getservbyname my_getservbyname
1597
1598 #ifdef CK_ANSIC
1599 globalref int (*C$$GA_UCX_GETSERVBYNAME)();
1600 extern void C$$TRANSLATE();
1601 extern void C$$SOCK_TRANSLATE();
1602 #else
1603 globalref int (*C$$GA_UCX_GETSERVBYNAME)();
1604 extern VOID C$$TRANSLATE();
1605 extern VOID C$$SOCK_TRANSLATE();
1606 #endif /* CK_ANSIC */
1607
1608 struct servent *
1609 my_getservbyname (service, proto) char *service, *proto; {
1610     static struct servent sent;
1611     struct iosb {
1612         union {
1613             unsigned long status;
1614             unsigned short st[2];
1615         } sb;
1616         unsigned long spare;
1617     } s;
1618     struct {
1619         struct iosb *s;
1620         char *serv;
1621         char *prot;
1622     } par;
1623     unsigned long e;
1624     char sbuf[30], pbuf[30];
1625     char *p;
1626
1627     debug(F111,"UCX getservbyname",service,(int)C$$GA_UCX_GETSERVBYNAME);
1628
1629     p = sbuf;
1630     ckstrncpy(p, service, 29);
1631     while (*p = toupper(*p), *p++) {}
1632     p = pbuf;
1633     ckstrncpy(p, proto, 29);
1634     while (*p = toupper(*p), *p++) {}
1635
1636     par.s = &s;
1637
1638     par.serv = "";
1639     par.prot = "";
1640     /* reset file pointer or something like that!?!? */
1641     e = (*C$$GA_UCX_GETSERVBYNAME)(&par, &sent, par.s);
1642     par.serv = sbuf;
1643     par.prot = pbuf;            /* that is don't care */
1644     e = (*C$$GA_UCX_GETSERVBYNAME)(&par, &sent, par.s);
1645     if ((long)e == -1L)
1646       return NULL;
1647     if ((e & 1) == 0L) {
1648         C$$TRANSLATE(e);
1649         return NULL;
1650     }
1651     if ((s.sb.st[0] & 1) == 0) {
1652         C$$SOCK_TRANSLATE(&s.sb.st[0]);
1653         return NULL;
1654     }
1655 /*
1656   sent.s_port is supposed to be returned by UCX in network byte order.
1657   However, UCX 2.0 through 2.0C did not do this; 2.0D and later do it.
1658   But there is no way of knowing which UCX version, so we have a user-settable
1659   runtime variable.  Note: UCX 2.0 was only for the VAX.
1660 */
1661     debug(F101,"UCX getservbyname port","",sent.s_port);
1662     debug(F101,"UCX getservbyname ntohs(port)","",ntohs(sent.s_port));
1663     if (ucx_port_bug) {
1664         sent.s_port = htons(sent.s_port);
1665         debug(F100,"UCX-PORT-BUG ON: swapping bytes","",0);
1666         debug(F101,"UCX swapped port","",sent.s_port);
1667         debug(F101,"UCX swapped ntohs(port)","",ntohs(sent.s_port));
1668     }
1669     return &sent;
1670 }
1671 #endif /* def OLDIP */
1672 #endif /* DEC_TCPIP */
1673 #endif /* EXCELAN */
1674
1675 int
1676 gettcpport() {
1677     return(svcnum);
1678 }
1679
1680 #endif /* TCPSOCKET */
1681
1682 #ifndef NOTCPOPTS
1683 #ifndef datageneral
1684 int
1685 ck_linger(sock, onoff, timo) int sock; int onoff; int timo; {
1686 /*
1687   The following, from William Bader, turns off the socket linger parameter,
1688   which makes a close() block until all data is sent.  "I don't think that
1689   disabling linger can ever cause kermit to lose data, but you telnet to a
1690   flaky server (or to our modem server when the modem is in use), disabling
1691   linger prevents kermit from hanging on the close if you try to exit."
1692
1693   Modified by Jeff Altman to be generally useful.
1694 */
1695 #ifdef SOL_SOCKET
1696 #ifdef SO_LINGER
1697     struct linger set_linger_opt;
1698     struct linger get_linger_opt;
1699     SOCKOPT_T x;
1700
1701 #ifdef IKSD
1702     if (!inserver)
1703 #endif /* IKSD */
1704       if (sock == -1 ||
1705         nettype != NET_TCPA && nettype != NET_TCPB &&
1706         nettype != NET_SSH || ttmdm >= 0) {
1707         tcp_linger = onoff;
1708         tcp_linger_tmo = timo;
1709         return(1);
1710     }
1711     x = sizeof(get_linger_opt);
1712     if (getsockopt(sock, SOL_SOCKET, SO_LINGER,
1713                     (char *)&get_linger_opt, &x)) {
1714         debug(F111,"TCP ck_linger can't get SO_LINGER",ck_errstr(),errno);
1715     } else if (x != sizeof(get_linger_opt)) {
1716 #ifdef OS2
1717         struct _linger16 {
1718             short s_linger;
1719             short s_onoff;
1720         } get_linger_opt16, set_linger_opt16;
1721         if ( x == sizeof(get_linger_opt16) ) {
1722             debug(F111,"TCP setlinger warning: SO_LINGER","len is 16-bit",x);
1723             if (getsockopt(sock,
1724                            SOL_SOCKET, SO_LINGER,
1725                            (char *)&get_linger_opt16, &x)
1726                 ) {
1727                 debug(F111,
1728                       "TCP ck_linger can't get SO_LINGER",ck_errstr(),errno);
1729             } else if (get_linger_opt16.s_onoff != onoff ||
1730                        get_linger_opt16.s_linger != timo)
1731             {
1732                 set_linger_opt16.s_onoff  = onoff;
1733                 set_linger_opt16.s_linger = timo;
1734                 if (setsockopt(sock,
1735                                SOL_SOCKET,
1736                                SO_LINGER,
1737                                (char *)&set_linger_opt16,
1738                                sizeof(set_linger_opt16))
1739                     ) {
1740                     debug(F111,
1741                           "TCP ck_linger can't set SO_LINGER",
1742                           ck_errstr(),
1743                           errno
1744                           );
1745                     tcp_linger = get_linger_opt16.s_onoff;
1746                     tcp_linger_tmo = get_linger_opt16.s_linger;
1747                 } else {
1748                     debug(F101,
1749                           "TCP ck_linger new SO_LINGER","",
1750                           set_linger_opt16.s_onoff);
1751                     tcp_linger = set_linger_opt16.s_onoff;
1752                     tcp_linger_tmo = set_linger_opt16.s_linger;
1753                     return 1;
1754                 }
1755             } else {
1756                 debug(F101,"TCP ck_linger SO_LINGER unchanged","",
1757                        get_linger_opt16.s_onoff);
1758                 tcp_linger = get_linger_opt16.s_onoff;
1759                 tcp_linger_tmo = get_linger_opt16.s_linger;
1760                 return 1;
1761             }
1762             return(0);
1763         }
1764 #endif /* OS2 */
1765         debug(F111,"TCP ck_linger error: SO_LINGER","len",x);
1766         debug(F111,"TCP ck_linger SO_LINGER",
1767               "expected len",sizeof(get_linger_opt));
1768         debug(F111,"TCP ck_linger SO_LINGER","linger_opt.l_onoff",
1769               get_linger_opt.l_onoff);
1770         debug(F111,"TCP linger SO_LINGER","linger_opt.l_linger",
1771                get_linger_opt.l_linger);
1772     } else if (get_linger_opt.l_onoff != onoff ||
1773                get_linger_opt.l_linger != timo) {
1774         set_linger_opt.l_onoff  = onoff;
1775         set_linger_opt.l_linger = timo;
1776         if (setsockopt(sock,
1777                        SOL_SOCKET,
1778                        SO_LINGER,
1779                        (char *)&set_linger_opt,
1780                        sizeof(set_linger_opt))) {
1781             debug(F111,"TCP ck_linger can't set SO_LINGER",ck_errstr(),errno);
1782             tcp_linger = get_linger_opt.l_onoff;
1783             tcp_linger_tmo = get_linger_opt.l_linger;
1784          } else {
1785              debug(F101,
1786                    "TCP ck_linger new SO_LINGER",
1787                    "",
1788                    set_linger_opt.l_onoff
1789                    );
1790              tcp_linger = set_linger_opt.l_onoff;
1791              tcp_linger_tmo = set_linger_opt.l_linger;
1792              return 1;
1793          }
1794     } else {
1795         debug(F101,"TCP ck_linger SO_LINGER unchanged","",
1796               get_linger_opt.l_onoff);
1797         tcp_linger = get_linger_opt.l_onoff;
1798         tcp_linger_tmo = get_linger_opt.l_linger;
1799         return 1;
1800     }
1801 #else
1802     debug(F100,"TCP ck_linger SO_LINGER not defined","",0);
1803 #endif /* SO_LINGER */
1804 #else
1805     debug(F100,"TCP ck_linger SO_SOCKET not defined","",0);
1806 #endif /* SOL_SOCKET */
1807     return(0);
1808 }
1809
1810 int
1811 sendbuf(sock,size) int sock; int size; {
1812 /*
1813   The following, from William Bader, allows changing of socket buffer sizes,
1814   in case that might affect performance.
1815
1816   Modified by Jeff Altman to be generally useful.
1817 */
1818 #ifdef SOL_SOCKET
1819 #ifdef SO_SNDBUF
1820     int i, j;
1821     SOCKOPT_T x;
1822
1823 #ifdef IKSD
1824     if (!inserver)
1825 #endif /* IKSD */
1826       if (sock == -1 ||
1827         nettype != NET_TCPA && nettype != NET_TCPB && nettype != NET_SSH
1828                 || ttmdm >= 0) {
1829         tcp_sendbuf = size;
1830         return 1;
1831     }
1832     x = sizeof(i);
1833     if (getsockopt(sock, SOL_SOCKET, SO_SNDBUF, (char *)&i, &x)) {
1834         debug(F111,"TCP sendbuf can't get SO_SNDBUF",ck_errstr(),errno);
1835     } else if (x != sizeof(i)) {
1836 #ifdef OS2
1837         short i16,j16;
1838         if (x == sizeof(i16)) {
1839             debug(F111,"TCP sendbuf warning: SO_SNDBUF","len is 16-bit",x);
1840             if (getsockopt(sock,
1841                            SOL_SOCKET, SO_SNDBUF,
1842                            (char *)&i16, &x)
1843                 ) {
1844                 debug(F111,"TCP sendbuf can't get SO_SNDBUF",
1845                       ck_errstr(),errno);
1846             } else if (size <= 0) {
1847                 tcp_sendbuf = i16;
1848                 debug(F101,"TCP sendbuf SO_SNDBUF retrieved","",i16);
1849                 return 1;
1850             } else if (i16 != size) {
1851                 j16 = size;
1852                 if (setsockopt(sock,
1853                                SOL_SOCKET,
1854                                SO_SNDBUF,
1855                                (char *)&j16,
1856                                sizeof(j16))
1857                     ) {
1858                     debug(F111,"TCP sendbuf can't set SO_SNDBUF",
1859                           ck_errstr(),errno);
1860                 } else {
1861                     debug(F101,"TCP sendbuf old SO_SNDBUF","",i16);
1862                     debug(F101,"TCP sendbuf new SO_SNDBUF","",j16);
1863                     tcp_sendbuf = size;
1864                     return 1;
1865                 }
1866             } else {
1867                 debug(F101,"TCP sendbuf SO_SNDBUF unchanged","",i16);
1868                 tcp_sendbuf = size;
1869                 return 1;
1870             }
1871             return(0);
1872         }
1873 #endif /* OS2 */
1874         debug(F111,"TCP sendbuf error: SO_SNDBUF","len",x);
1875         debug(F111,"TCP sendbuf SO_SNDBUF","expected len",sizeof(i));
1876         debug(F111,"TCP sendbuf SO_SNDBUF","i",i);
1877     } else if (size <= 0) {
1878         tcp_sendbuf = i;
1879         debug(F101,"TCP sendbuf SO_SNDBUF retrieved","",i);
1880         return 1;
1881     } else if (i != size) {
1882         j = size;
1883         if (setsockopt(sock, SOL_SOCKET, SO_SNDBUF, (char *)&j, sizeof(j))) {
1884             debug(F111,"TCP sendbuf can't set SO_SNDBUF",ck_errstr(),errno);
1885             tcp_sendbuf = i;
1886         } else {
1887             debug(F101,"TCP sendbuf old SO_SNDBUF","",i);
1888             debug(F101,"TCP sendbuf new SO_SNDBUF","",j);
1889             tcp_sendbuf = size;
1890             return 1;
1891         }
1892     } else {
1893         debug(F101,"TCP sendbuf SO_SNDBUF unchanged","",i);
1894         tcp_sendbuf = size;
1895         return 1;
1896     }
1897 #else
1898     debug(F100,"TCP sendbuf SO_SNDBUF not defined","",0);
1899 #endif /* SO_SNDBUF */
1900 #else
1901     debug(F100,"TCP sendbuf SO_SOCKET not defined","",0);
1902 #endif /* SOL_SOCKET */
1903     return(0);
1904 }
1905
1906 int
1907 recvbuf(sock,size) int sock; int size; {
1908 /*
1909   The following, from William Bader, allows changing of socket buffer sizes,
1910   in case that might affect performance.
1911
1912   Modified by Jeff Altman to be generally useful.
1913 */
1914 #ifdef SOL_SOCKET
1915 #ifdef SO_RCVBUF
1916     int i, j;
1917     SOCKOPT_T x;
1918
1919 #ifdef IKSD
1920     if (!inserver)
1921 #endif /* IKSD */
1922       if (sock == -1 ||
1923           nettype != NET_TCPA && nettype != NET_TCPB &&
1924           nettype != NET_SSH || ttmdm >= 0) {
1925         tcp_recvbuf = size;
1926         return(1);
1927     }
1928     x = sizeof(i);
1929     if (getsockopt(sock, SOL_SOCKET, SO_RCVBUF, (char *)&i, &x)) {
1930         debug(F111,"TCP recvbuf can't get SO_RCVBUF",ck_errstr(),errno);
1931     } else if (x != sizeof(i)) {
1932 #ifdef OS2
1933         short i16,j16;
1934         if ( x == sizeof(i16) ) {
1935             debug(F111,"TCP recvbuf warning: SO_RCVBUF","len is 16-bit",x);
1936             if (getsockopt(sock,
1937                            SOL_SOCKET, SO_RCVBUF,
1938                            (char *)&i16, &x)
1939                 ) {
1940                 debug(F111,"TCP recvbuf can't get SO_RCVBUF",
1941                       ck_errstr(),errno);
1942             } else if (size <= 0) {
1943                 tcp_recvbuf = i16;
1944                 debug(F101,"TCP recvbuf SO_RCVBUF retrieved","",i16);
1945                 return 1;
1946             } else if (i16 != size) {
1947                 j16 = size;
1948                 if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF, (char *)&j16,
1949                                sizeof(j16))) {
1950                     debug(F111,"TCP recvbuf can' set SO_RCVBUF",
1951                           ck_errstr(),errno);
1952                 } else {
1953                     debug(F101,"TCP recvbuf old SO_RCVBUF","",i16);
1954                     debug(F101,"TCP recvbuf new SO_RCVBUF","",j16);
1955                     tcp_recvbuf = size;
1956                     return 1;
1957                 }
1958             } else {
1959                 debug(F101,"TCP recvbuf SO_RCVBUF unchanged","",i16);
1960                 tcp_recvbuf = size;
1961                 return 1;
1962             }
1963             return(0);
1964         }
1965 #endif /* OS2 */
1966         debug(F111,"TCP recvbuf error: SO_RCVBUF","len",x);
1967         debug(F111,"TCP recvbuf SO_RCVBUF","expected len",sizeof(i));
1968         debug(F111,"TCP recvbuf SO_RCVBUF","i",i);
1969     } else if (size <= 0) {
1970         tcp_recvbuf = i;
1971         debug(F101,"TCP recvbuf SO_RCVBUF retrieved","",i);
1972         return 1;
1973     } else if (i != size) {
1974         j = size;
1975         if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF, (char *)&j, sizeof(j))) {
1976             debug(F111,"TCP recvbuf can't set SO_RCVBUF",ck_errstr(),errno);
1977             tcp_recvbuf = i;
1978         } else {
1979             debug(F101,"TCP recvbuf old SO_RCVBUF","",i);
1980             debug(F101,"TCP recvbuf new SO_RCVBUF","",j);
1981             tcp_recvbuf = size;
1982             return 1;
1983         }
1984     } else {
1985         debug(F101,"TCP recvbuf SO_RCVBUF unchanged","",i);
1986         tcp_recvbuf = size;
1987         return 1;
1988     }
1989 #else
1990     debug(F100,"TCP recvbuf SO_RCVBUF not defined","",0);
1991 #endif /* SO_RCVBUF */
1992 #else
1993     debug(F100,"TCP recvbuf SO_SOCKET not defined","",0);
1994 #endif /* SOL_SOCKET */
1995     return 0;
1996 }
1997
1998 int
1999 keepalive(sock,onoff) int sock; int onoff; {
2000 #ifdef SOL_SOCKET
2001 #ifdef SO_KEEPALIVE
2002     int get_keepalive_opt;
2003     int set_keepalive_opt;
2004     SOCKOPT_T x;
2005
2006     debug(F111,"TCP keepalive","sock",sock);
2007     debug(F111,"TCP keepalive","nettype",nettype);
2008     debug(F111,"TCP keepalive","ttmdm",ttmdm);
2009
2010 #ifdef IKSD
2011     if (!inserver)
2012 #endif /* IKSD */
2013       if (sock == -1 ||
2014         nettype != NET_TCPA && nettype != NET_TCPB && nettype != NET_SSH
2015                 || ttmdm >= 0) {
2016         tcp_keepalive = onoff;
2017         return 1;
2018     }
2019     x = sizeof(get_keepalive_opt);
2020     if (getsockopt(sock,
2021                    SOL_SOCKET, SO_KEEPALIVE, (char *)&get_keepalive_opt, &x)) {
2022         debug(F111,"TCP keepalive can't get SO_KEEPALIVE",ck_errstr(),errno);
2023     } else if (x != sizeof(get_keepalive_opt)) {
2024 #ifdef OS2
2025         short get_keepalive_opt16;
2026         short set_keepalive_opt16;
2027         if (x == sizeof(get_keepalive_opt16)) {
2028             debug(F111,"TCP keepalive warning: SO_KEEPALIVE",
2029                   "len is 16-bit",x);
2030             if (getsockopt(sock,
2031                            SOL_SOCKET, SO_KEEPALIVE,
2032                            (char *)&get_keepalive_opt16, &x)
2033                 ) {
2034                 debug(F111,
2035                       "TCP keepalive can't get SO_KEEPALIVE",
2036                       ck_errstr(),
2037                       errno
2038                       );
2039             } else if (get_keepalive_opt16 != onoff) {
2040                 set_keepalive_opt16 = onoff;
2041                 if (setsockopt(sock,
2042                                SOL_SOCKET,
2043                                SO_KEEPALIVE,
2044                                (char *)&set_keepalive_opt16,
2045                                sizeof(set_keepalive_opt16))
2046                     ) {
2047                     debug(F111,
2048                           "TCP keepalive can't clear SO_KEEPALIVE",
2049                           ck_errstr(),
2050                           errno
2051                           );
2052                     tcp_keepalive = get_keepalive_opt16;
2053                 } else {
2054                     debug(F101,
2055                           "TCP keepalive new SO_KEEPALIVE","",
2056                           set_keepalive_opt16);
2057                     tcp_keepalive = set_keepalive_opt16;
2058                     return 1;
2059                 }
2060             } else {
2061                 debug(F101,"TCP keepalive SO_KEEPALIVE unchanged","",
2062                       get_keepalive_opt16);
2063                 tcp_keepalive = onoff;
2064                 return 1;
2065             }
2066             return(0);
2067         }
2068 #endif /* OS2 */
2069         debug(F111,"TCP keepalive error: SO_KEEPALIVE","len",x);
2070         debug(F111,
2071               "TCP keepalive SO_KEEPALIVE",
2072               "expected len",
2073               sizeof(get_keepalive_opt)
2074               );
2075         debug(F111,
2076               "TCP keepalive SO_KEEPALIVE",
2077               "keepalive_opt",
2078               get_keepalive_opt
2079               );
2080     } else if (get_keepalive_opt != onoff) {
2081             set_keepalive_opt = onoff;
2082             if (setsockopt(sock,
2083                             SOL_SOCKET,
2084                             SO_KEEPALIVE,
2085                             (char *)&set_keepalive_opt,
2086                             sizeof(set_keepalive_opt))
2087                 ) {
2088                 debug(F111,
2089                       "TCP keepalive can't clear SO_KEEPALIVE",
2090                       ck_errstr(),
2091                       errno
2092                       );
2093                 tcp_keepalive = get_keepalive_opt;
2094             } else {
2095                 debug(F101,
2096                       "TCP keepalive new SO_KEEPALIVE",
2097                       "",
2098                       set_keepalive_opt
2099                       );
2100                 tcp_keepalive = onoff;
2101                 return 1;
2102             }
2103         } else {
2104             debug(F101,"TCP keepalive SO_KEEPALIVE unchanged",
2105                   "",
2106                   get_keepalive_opt
2107                   );
2108             tcp_keepalive = onoff;
2109             return 1;
2110     }
2111 #else
2112     debug(F100,"TCP keepalive SO_KEEPALIVE not defined","",0);
2113 #endif /* SO_KEEPALIVE */
2114 #else
2115     debug(F100,"TCP keepalive SO_SOCKET not defined","",0);
2116 #endif /* SOL_SOCKET */
2117     return(0);
2118 }
2119
2120 int
2121 dontroute(sock,onoff) int sock; int onoff; {
2122 #ifdef SOL_SOCKET
2123 #ifdef SO_DONTROUTE
2124     int get_dontroute_opt;
2125     int set_dontroute_opt;
2126     SOCKOPT_T x;
2127
2128 #ifdef IKSD
2129     if (!inserver)
2130 #endif /* IKSD */
2131       if (sock == -1 ||
2132         nettype != NET_TCPA && nettype != NET_TCPB && nettype != NET_SSH
2133                 || ttmdm >= 0) {
2134         tcp_dontroute = onoff;
2135         return 1;
2136     }
2137     x = sizeof(get_dontroute_opt);
2138     if (getsockopt(sock,
2139                    SOL_SOCKET, SO_DONTROUTE, (char *)&get_dontroute_opt, &x)) {
2140         debug(F111,"TCP dontroute can't get SO_DONTROUTE",ck_errstr(),errno);
2141     } else if (x != sizeof(get_dontroute_opt)) {
2142 #ifdef OS2
2143         short get_dontroute_opt16;
2144         short set_dontroute_opt16;
2145         if (x == sizeof(get_dontroute_opt16)) {
2146             debug(F111,"TCP dontroute warning: SO_DONTROUTE",
2147                   "len is 16-bit",x);
2148             if (getsockopt(sock,
2149                            SOL_SOCKET, SO_DONTROUTE,
2150                            (char *)&get_dontroute_opt16, &x)
2151                 ) {
2152                 debug(F111,
2153                       "TCP dontroute can't get SO_DONTROUTE",
2154                       ck_errstr(),
2155                       errno
2156                       );
2157             } else if (get_dontroute_opt16 != onoff) {
2158                 set_dontroute_opt16 = onoff;
2159                 if (setsockopt(sock,
2160                                SOL_SOCKET,
2161                                SO_DONTROUTE,
2162                                (char *)&set_dontroute_opt16,
2163                                sizeof(set_dontroute_opt16))
2164                     ) {
2165                     debug(F111,
2166                           "TCP dontroute can't clear SO_DONTROUTE",
2167                           ck_errstr(),
2168                           errno
2169                           );
2170                     tcp_dontroute = get_dontroute_opt16;
2171                 } else {
2172                     debug(F101,
2173                           "TCP dontroute new SO_DONTROUTE","",
2174                           set_dontroute_opt16);
2175                     tcp_dontroute = set_dontroute_opt16;
2176                     return 1;
2177                 }
2178             } else {
2179                 debug(F101,"TCP dontroute SO_DONTROUTE unchanged","",
2180                       get_dontroute_opt16);
2181                 tcp_dontroute = onoff;
2182                 return 1;
2183             }
2184             return(0);
2185         }
2186 #endif /* OS2 */
2187         debug(F111,"TCP dontroute error: SO_DONTROUTE","len",x);
2188         debug(F111,
2189               "TCP dontroute SO_DONTROUTE",
2190               "expected len",
2191               sizeof(get_dontroute_opt)
2192               );
2193         debug(F111,
2194               "TCP dontroute SO_DONTROUTE",
2195               "dontroute_opt",
2196               get_dontroute_opt
2197               );
2198     } else if (get_dontroute_opt != onoff) {
2199             set_dontroute_opt = onoff;
2200             if (setsockopt(sock,
2201                             SOL_SOCKET,
2202                             SO_DONTROUTE,
2203                             (char *)&set_dontroute_opt,
2204                             sizeof(set_dontroute_opt))
2205                 ) {
2206                 debug(F111,
2207                       "TCP dontroute can't clear SO_DONTROUTE",
2208                       ck_errstr(),
2209                       errno
2210                       );
2211                 tcp_dontroute = get_dontroute_opt;
2212             } else {
2213                 debug(F101,
2214                       "TCP dontroute new SO_DONTROUTE",
2215                       "",
2216                       set_dontroute_opt
2217                       );
2218                 tcp_dontroute = onoff;
2219                 return 1;
2220             }
2221         } else {
2222             debug(F101,"TCP dontroute SO_DONTROUTE unchanged",
2223                   "",
2224                   get_dontroute_opt
2225                   );
2226             tcp_dontroute = onoff;
2227             return 1;
2228     }
2229 #else
2230     debug(F100,"TCP dontroute SO_DONTROUTE not defined","",0);
2231 #endif /* SO_DONTROUTE */
2232 #else
2233     debug(F100,"TCP dontroute SO_SOCKET not defined","",0);
2234 #endif /* SOL_SOCKET */
2235     return(0);
2236 }
2237
2238 int
2239 no_delay(sock,onoff)  int sock; int onoff; {
2240 #ifdef SOL_SOCKET
2241 #ifdef TCP_NODELAY
2242     int get_nodelay_opt;
2243     int set_nodelay_opt;
2244     SOCKOPT_T x;
2245
2246 #ifdef IKSD
2247     if (!inserver)
2248 #endif /* IKSD */
2249       if (sock == -1 ||
2250         nettype != NET_TCPA && nettype != NET_TCPB && nettype != NET_SSH
2251                 || ttmdm >= 0) {
2252         tcp_nodelay = onoff;
2253         return(1);
2254     }
2255     x = sizeof(get_nodelay_opt);
2256     if (getsockopt(sock,IPPROTO_TCP,TCP_NODELAY,
2257                    (char *)&get_nodelay_opt,&x)) {
2258         debug(F111,
2259               "TCP no_delay can't get TCP_NODELAY",
2260               ck_errstr(),
2261               errno);
2262     } else if (x != sizeof(get_nodelay_opt)) {
2263 #ifdef OS2
2264         short get_nodelay_opt16;
2265         short set_nodelay_opt16;
2266         if (x == sizeof(get_nodelay_opt16)) {
2267             debug(F111,"TCP no_delay warning: TCP_NODELAY","len is 16-bit",x);
2268             if (getsockopt(sock,
2269                            IPPROTO_TCP, TCP_NODELAY,
2270                            (char *)&get_nodelay_opt16, &x)
2271                 ) {
2272                 debug(F111,
2273                       "TCP no_delay can't get TCP_NODELAY",
2274                       ck_errstr(),
2275                       errno);
2276             } else if (get_nodelay_opt16 != onoff) {
2277                 set_nodelay_opt16 = onoff;
2278                 if (setsockopt(sock,
2279                                IPPROTO_TCP,
2280                                TCP_NODELAY,
2281                                (char *)&set_nodelay_opt16,
2282                                sizeof(set_nodelay_opt16))
2283                     ) {
2284                     debug(F111,
2285                           "TCP no_delay can't clear TCP_NODELAY",
2286                           ck_errstr(),
2287                           errno);
2288                     tcp_nodelay = get_nodelay_opt16;
2289                 } else {
2290                     debug(F101,
2291                           "TCP no_delay new TCP_NODELAY",
2292                           "",
2293                           set_nodelay_opt16);
2294                     tcp_nodelay = onoff;
2295                     return 1;
2296                 }
2297             } else {
2298                 debug(F101,"TCP no_delay TCP_NODELAY unchanged","",
2299                       get_nodelay_opt16);
2300                 tcp_nodelay = onoff;
2301                 return 1;
2302             }
2303             return(0);
2304         }
2305 #endif /* OS2 */
2306         debug(F111,"TCP no_delay error: TCP_NODELAY","len",x);
2307         debug(F111,"TCP no_delay TCP_NODELAY","expected len",
2308               sizeof(get_nodelay_opt));
2309         debug(F111,"TCP no_delay TCP_NODELAY","nodelay_opt",get_nodelay_opt);
2310     } else if (get_nodelay_opt != onoff) {
2311         set_nodelay_opt = onoff;
2312         if (setsockopt(sock,
2313                        IPPROTO_TCP,
2314                        TCP_NODELAY,
2315                        (char *)&set_nodelay_opt,
2316                        sizeof(set_nodelay_opt))) {
2317             debug(F111,
2318                   "TCP no_delay can't clear TCP_NODELAY",
2319                   ck_errstr(),
2320                   errno
2321                   );
2322             tcp_nodelay = get_nodelay_opt;
2323         } else {
2324             debug(F101,"TCP no_delay new TCP_NODELAY","",set_nodelay_opt);
2325             tcp_nodelay = onoff;
2326             return 1;
2327         }
2328     } else {
2329         debug(F101,"TCP no_delay TCP_NODELAY unchanged","",get_nodelay_opt);
2330         tcp_nodelay = onoff;
2331         return(1);
2332     }
2333 #else
2334     debug(F100,"TCP no_delay TCP_NODELAY not defined","",0);
2335 #endif /* TCP_NODELAY */
2336 #else
2337     debug(F100,"TCP no_delay SO_SOCKET not defined","",0);
2338 #endif /* SOL_SOCKET */
2339     return 0;
2340 }
2341 #endif /* datageneral */
2342 #endif /* NOTCPOPTS */
2343
2344 #ifdef SUNX25
2345 #ifndef X25_WR_FACILITY
2346 /* For Solaris 2.3 / SunLink 8.x - see comments in ckcnet.h */
2347 void
2348 bzero(s,n) char *s; int n; {
2349     memset(s,0,n);
2350 }
2351 #endif /* X25_WR_FACILITY */
2352 #endif /* SUNX25 */
2353
2354 #ifdef TCPSOCKET
2355 #ifndef OS2
2356 #ifndef NOLISTEN
2357
2358 #ifdef BSDSELECT
2359 #ifndef VMS
2360 #ifndef BELLV10
2361 #ifndef datageneral
2362 #ifdef hp9000s500                       /* HP-9000/500 HP-U 5.21 */
2363 #include <time.h>
2364 #else
2365
2366 /****** THIS SECTION ADDED BY STEVE RANCE - OS9 NETWORK SERVER
2367 *       ------------------------------------------------------
2368 *
2369 *       Due to OS9's Lack of a select() call, the following seems to be
2370 *       enough to fool the rest of the code into compiling. The only
2371 *       effect that I can see is using control L to refresh the status
2372 *       display gets qued up until some network packets arrive.
2373 *
2374 *       This solution is by no means elegant but works enough to be
2375 *       a (the) solution.
2376 *
2377 *       Also with the defines I had specified in my makefile I had to
2378 *       have an #endif right at the end of the file when compiling.
2379 *       I did not bother speding time to find out why.
2380 *
2381 *       COPTS   = -to=osk -d=OSK -d=TCPSOCKET -d=SELECT -d=VOID=void -d=SIG_V \
2382 *          -d=DYNAMIC -d=PARSENSE -d=KANJI -d=MYCURSES -d=ZFCDAT \
2383 *          -d=CK_APC -d=CK_REDIR -d=RENAME -d=CK_TTYFD -d=NOOLDMODEMS \
2384 *          -d=CK_ANSIC -d=CK_XYZ -tp=68040d -l=netdb.l -l=socklib.l \
2385 *          -l=termlib.l -l=math.l -l=sys_clib.l
2386 *
2387 *       stever@ozemail.com.au
2388 */
2389
2390 #ifdef  OSK
2391 #define BSDSELECT                       /* switch on BSD select code */
2392 #define FD_SETSIZE 32                   /* Max # of paths in OS9 */
2393 #define FD_ZERO(p)                      ((*p)=0)
2394 #define FD_SET(n,b)                     ((*b)|=(1<<(n)))
2395 #define FD_ISSET(n,b)           1       /* always say data is ready */
2396 #define select(a,b,c,d,e)       1       /* always say 1 path has data */
2397 typedef int     fd_set;                 /* keep BSD Code Happy */
2398 struct timeval {int tv_sec,tv_usec;};   /* keep BSD Code Happy */
2399
2400 /****** END OF OS9 MODS FROM STEVE RANCE **************************/
2401 #endif /* OSK */
2402
2403 #include <sys/time.h>
2404 #endif /* hp9000s500 */
2405 #endif /* datageneral */
2406 #endif /* BELLV10 */
2407 #endif /* VMS */
2408 #ifdef SELECT_H
2409 #include <sys/select.h>
2410 #endif /* SELECT_H */
2411 #endif /* BSDSELECT */
2412
2413 #ifdef SELECT
2414 #ifdef CK_SCOV5
2415 #include <sys/select.h>
2416 #endif /* CK_SCOV5 */
2417 #endif /* SELECT */
2418
2419 #ifdef NOTUSED
2420 /* T C P S O C K E T _ O P E N -- Open a preexisting socket number */
2421
2422 int
2423 tcpsocket_open(name,lcl,nett,timo) char * name; int * lcl; int nett; int timo {
2424     int on = 1;
2425     static struct servent *service, servrec;
2426     static struct hostent *host;
2427     static struct sockaddr_in saddr;
2428     static
2429 #ifdef UCX50
2430       unsigned
2431 #endif /* UCX50 */
2432       int saddrlen;
2433 #ifdef BSDSELECT
2434     fd_set rfds;
2435     struct timeval tv;
2436 #else
2437 #ifdef BELLSELECT
2438     fd_set rfds;
2439 #else
2440     fd_set rfds;
2441     fd_set rfds;
2442     struct timeval {
2443         long tv_sec;
2444         long tv_usec;
2445     } tv;
2446 #endif /* BELLSELECT */
2447 #endif /* BSDSELECT */
2448
2449     debug(F101,"tcpsocket_open nett","",nett);
2450     *ipaddr = '\0';
2451
2452     if (nett != NET_TCPB)
2453       return(-1);                       /* BSD socket support */
2454
2455     netclos();                          /* Close any previous connection. */
2456     ckstrncpy(namecopy, name, NAMECPYL); /* Copy the hostname. */
2457 #ifdef COMMENT
2458     /* Jeff's version from 30 Dec 2005 doesn't inhibit Telnet */
2459     if (ttnproto != NP_TCPRAW &&
2460         ttnproto != NP_SSL_RAW &&
2461         ttnproto != NP_TLS_RAW)
2462       ttnproto = NP_NONE;               /* No protocol selected yet. */
2463 #else
2464     /* fdc's version from 4 Dec 2005 works ok */
2465     if (ttnproto != NP_TCPRAW)
2466       ttnproto = NP_NONE;               /* No protocol selected yet. */
2467 #endif  /* COMMENT */
2468     debug(F110,"tcpsocket_open namecopy",namecopy,0);
2469
2470     /* Assign the socket number to ttyfd and then fill in tcp structures */
2471     ttyfd = atoi(&name[1]);
2472     debug(F111,"tcpsocket_open","ttyfd",ttyfd);
2473
2474 #ifndef NOTCPOPTS
2475 #ifdef SOL_SOCKET
2476     setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
2477
2478 #ifndef datageneral
2479 #ifdef TCP_NODELAY
2480     no_delay(ttyfd,tcp_nodelay);
2481 #endif /* TCP_NODELAY */
2482 #ifdef SO_KEEPALIVE
2483     keepalive(ttyfd,tcp_keepalive);
2484 #endif /* SO_KEEPALIVE */
2485 #ifdef SO_LINGER
2486     ck_linger(ttyfd,tcp_linger, tcp_linger_tmo);
2487 #endif /* SO_LINGER */
2488 #ifdef SO_SNDBUF
2489     sendbuf(ttyfd,tcp_sendbuf);
2490 #endif /* SO_SNDBUF */
2491 #ifdef SO_RCVBUF
2492     recvbuf(ttyfd,tcp_recvbuf);
2493 #endif /* SO_RCVBUF */
2494 #endif /* datageneral */
2495 #endif /* SOL_SOCKET */
2496 #endif /* NOTCPOPTS */
2497
2498 #ifdef NT_TCP_OVERLAPPED
2499     OverlappedWriteInit();
2500     OverlappedReadInit();
2501 #endif /* NT_TCP_OVERLAPPED */
2502
2503
2504     /* Get the name of the host we are connected to */
2505
2506     saddrlen = sizeof(saddr);
2507     getpeername(ttyfd,(struct sockaddr *)&saddr,&saddrlen);
2508
2509     ckstrncpy(ipaddr,(char *)inet_ntoa(saddr.sin_addr),20);
2510
2511     if (tcp_rdns == SET_ON
2512 #ifdef CK_KERBEROS
2513         || tcp_rdns == SET_AUTO &&
2514          (ck_krb5_is_installed() || ck_krb4_is_installed())
2515 #endif /* CK_KERBEROS */
2516 #ifndef NOHTTP
2517           && (tcp_http_proxy == NULL)
2518 #endif /* NOHTTP */
2519 #ifdef CK_SSL
2520           && !(ssl_only_flag || tls_only_flag)
2521 #endif /* CK_SSL */
2522          ) {                            /* Reverse DNS */
2523         if (!quiet) {
2524             printf(" Reverse DNS Lookup... ");
2525             fflush(stdout);
2526         }
2527         host = gethostbyaddr((char *)&saddr.sin_addr,4,PF_INET);
2528         debug(F110,"tcpsocket_open gethostbyaddr",host ? "OK" : "FAILED",0);
2529         if (host) {
2530             host = ck_copyhostent(host);
2531             debug(F100,"tcpsocket_open gethostbyaddr != NULL","",0);
2532             if (!quiet) {
2533                 printf("(OK)\n");
2534                 fflush(stdout);
2535             }
2536             ckstrncpy(name, host->h_name, 80);
2537             ckstrncat(name, ":", 80);
2538             ckstrncat(name,ckuitoa(ntohs(saddr.sin_port)), 80);
2539             if (!quiet
2540 #ifndef NOICP
2541                 && !doconx
2542 #endif /* NOICP */
2543                 )
2544               printf("%s connected on port %d\n",
2545                    host->h_name,
2546                    ntohs(saddr.sin_port)
2547                    );
2548         } else if (!quiet)
2549           printf("Failed\n");
2550     } else if (!quiet)
2551       printf("(OK)\n");
2552
2553     if (tcp_rdns != SET_ON || !host) {
2554         ckstrncpy(name,ipaddr,80);
2555         ckstrncat(name,":",80);
2556         ckstrncat(name,ckuitoa(ntohs(saddr.sin_port)),80);
2557         if (!quiet
2558 #ifdef NOICP
2559             && !doconx
2560 #endif /* NOICP */
2561             )
2562           printf("%s connected on port %d\n",ipaddr,ntohs(saddr.sin_port));
2563     }
2564     if (!quiet) fflush(stdout);
2565     ttnet = nett;                       /* TCP/IP (sockets) network */
2566
2567 #ifdef RLOGCODE
2568     if (ntohs(saddr.sin_port) == 513)
2569         ttnproto = NP_LOGIN;
2570     else
2571 #endif /* RLOGCODE */
2572     /* Assume the service is TELNET. */
2573 #ifdef COMMENT
2574       /* Jeff's code from 2005/12/30 */
2575       if (ttnproto != NP_TCP_RAW &&
2576           ttnproto != NP_SSL_RAW &&
2577           ttnproto != NP_TLS_RAW)
2578 #else
2579       /* fdc's code from 2005/12/04 */
2580       if (ttnproto != NP_TCPRAW)
2581 #endif  /* COMMENT */
2582         ttnproto = NP_TELNET;           /* Yes, set global flag. */
2583 #ifdef CK_SECURITY
2584     /* Before Initialization Telnet/Rlogin Negotiations Init Kerberos */
2585     ck_auth_init((tcp_rdns && host && host->h_name && host->h_name[0]) ?
2586                 host->h_name : ipaddr,
2587                 ipaddr,
2588                 uidbuf,
2589                 ttyfd
2590                 );
2591 #endif /* CK_SECURITY */
2592     if (tn_ini() < 0)                   /* Start/Reset TELNET negotiations */
2593       if (ttchk() < 0)                  /* Did it fail due to connect loss? */
2594         return(-1);
2595
2596     if (*lcl < 0) *lcl = 1;             /* Local mode. */
2597
2598     return(0);                          /* Done. */
2599 }
2600 #endif /* NOTUSED */
2601
2602 /*  T C P S R V _ O P E N  --  Open a TCP/IP Server connection  */
2603 /*
2604   Calling conventions same as ttopen(), except third argument is network
2605   type rather than modem type.
2606 */
2607 int
2608 tcpsrv_open(name,lcl,nett,timo) char * name; int * lcl; int nett; int timo; {
2609     char *p;
2610     int i, x;
2611     SOCKOPT_T on = 1;
2612     int ready_to_accept = 0;
2613     static struct servent *service, *service2, servrec;
2614     static struct hostent *host;
2615     static struct sockaddr_in saddr;
2616     struct sockaddr_in l_addr;
2617     GSOCKNAME_T l_slen;
2618 #ifdef UCX50
2619     static u_int saddrlen;
2620 #else
2621     static SOCKOPT_T saddrlen;
2622 #endif /* UCX50 */
2623
2624 #ifdef BSDSELECT
2625     fd_set rfds;
2626     struct timeval tv;
2627 #else
2628 #ifdef BELLSELCT
2629     fd_set rfds;
2630 #else
2631     fd_set rfds;
2632     struct timeval {
2633         long tv_sec;
2634         long tv_usec;
2635     } tv;
2636 #endif /* BELLSELECT */
2637 #endif /* BSDSELECT */
2638 #ifdef CK_SSL
2639     int ssl_failed = 0;
2640 #endif /* CK_SSL */
2641
2642     debug(F101,"tcpsrv_open nett","",nett);
2643     *ipaddr = '\0';
2644
2645     if (nett != NET_TCPB)
2646       return(-1);                       /* BSD socket support */
2647
2648     netclos();                          /* Close any previous connection. */
2649     ckstrncpy(namecopy, name, NAMECPYL); /* Copy the hostname. */
2650     /* Don't do this. */
2651 #ifdef COMMENT
2652     /* fdc */
2653     if (ttnproto != NP_TCPRAW)
2654       ttnproto = NP_NONE;               /* No protocol selected yet. */
2655 #endif  /* COMMENT */
2656 #ifdef COMMENT
2657     /* Jeff */
2658     if (ttnproto != NP_TCP_RAW &&
2659         ttnproto != NP_SSL_RAW &&
2660         ttnproto != NP_TLS_RAW)
2661       ttnproto = NP_NONE;               /* No protocol selected yet. */
2662 #endif /* COMMENT */
2663     debug(F110,"tcpsrv_open namecopy",namecopy,0);
2664
2665     p = namecopy;                       /* Was a service requested? */
2666     while (*p != '\0' && *p != ':')
2667       p++; /* Look for colon */
2668     if (*p == ':') {                    /* Have a colon */
2669         *p++ = '\0';                    /* Get service name or number */
2670     } else {                            /* Otherwise use kermit */
2671         p = "kermit";
2672     }
2673     debug(F110,"tcpsrv_open service requested",p,0);
2674     if (isdigit(*p)) {                  /* Use socket number without lookup */
2675         service = &servrec;
2676         service->s_port = htons((unsigned short)atoi(p));
2677     } else {                            /* Otherwise lookup the service name */
2678         service = getservbyname(p, "tcp");
2679     }
2680     if (!service && !strcmp("kermit",p)) { /* Use Kermit service port */
2681         service = &servrec;
2682         service->s_port = htons(1649);
2683     }
2684 #ifdef RLOGCODE
2685     if (service && !strcmp("login",p) && service->s_port != htons(513)) {
2686         fprintf(stderr,
2687                 "  Warning: login service on port %d instead of port 513\n",
2688                  ntohs(service->s_port));
2689         fprintf(stderr, "  Edit SERVICES file if RLOGIN fails to connect.\n");
2690         debug(F101,"tcpsrv_open login on port","",ntohs(service->s_port));
2691     }
2692 #endif /* RLOGCODE */
2693     if (!service) {
2694         fprintf(stderr, "Cannot find port for service: %s\n", p);
2695         debug(F111,"tcpsrv_open can't get service",p,errno);
2696         errno = 0;                      /* rather than mislead */
2697         return(-1);
2698     }
2699
2700     /* If we currently have a listen active but port has changed then close */
2701
2702     debug(F101,"tcpsrv_open checking previous connection","",tcpsrfd);
2703     debug(F101,"tcpsrv_open previous tcpsrv_port","",tcpsrv_port);
2704     if (tcpsrfd != -1 &&
2705         tcpsrv_port != ntohs((unsigned short)service->s_port)) {
2706         debug(F100,"tcpsrv_open closing previous connection","",0);
2707 #ifdef TCPIPLIB
2708         socket_close(tcpsrfd);
2709 #else
2710         close(tcpsrfd);
2711 #endif /* TCPIPLIB */
2712         tcpsrfd = -1;
2713     }
2714     debug(F100,"tcpsrv_open tcpsrfd","",tcpsrfd);
2715     if (tcpsrfd == -1) {
2716
2717         /* Set up socket structure and get host address */
2718
2719         bzero((char *)&saddr, sizeof(saddr));
2720         debug(F100,"tcpsrv_open bzero ok","",0);
2721         saddr.sin_family = AF_INET;
2722         if (tcp_address) {
2723 #ifdef INADDRX
2724             inaddrx = inet_addr(tcp_address);
2725             saddr.sin_addr.s_addr = *(unsigned long *)&inaddrx;
2726 #else
2727             saddr.sin_addr.s_addr = inet_addr(tcp_address);
2728 #endif /* INADDRX */
2729         } else
2730           saddr.sin_addr.s_addr = INADDR_ANY;
2731
2732         /* Get a file descriptor for the connection. */
2733
2734         saddr.sin_port = service->s_port;
2735         ipaddr[0] = '\0';
2736
2737         debug(F100,"tcpsrv_open calling socket","",0);
2738         if ((tcpsrfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
2739             perror("TCP socket error");
2740             debug(F101,"tcpsrv_open socket error","",errno);
2741             return (-1);
2742         }
2743         errno = 0;
2744
2745         /* Specify the Port may be reused */
2746
2747         debug(F100,"tcpsrv_open calling setsockopt","",0);
2748         x = setsockopt(tcpsrfd,
2749                        SOL_SOCKET,SO_REUSEADDR,(char *)&on,sizeof on);
2750         debug(F101,"tcpsrv_open setsockopt","",x);
2751
2752        /* Now bind to the socket */
2753         printf("\nBinding socket to port %d ...\n",
2754                ntohs((unsigned short)service->s_port));
2755         if (bind(tcpsrfd, (struct sockaddr *)&saddr, sizeof(saddr)) < 0) {
2756             i = errno;                  /* Save error code */
2757 #ifdef TCPIPLIB
2758             socket_close(tcpsrfd);
2759 #else /* TCPIPLIB */
2760             close(tcpsrfd);
2761 #endif /* TCPIPLIB */
2762             tcpsrfd = -1;
2763             tcpsrv_port = 0;
2764             ttyfd = -1;
2765             wasclosed = 1;
2766             errno = i;                  /* and report this error */
2767             debug(F101,"tcpsrv_open bind errno","",errno);
2768             printf("?Unable to bind to socket (errno = %d)\n",errno);
2769             return(-1);
2770         }
2771         debug(F100,"tcpsrv_open bind OK","",0);
2772         printf("Listening ...\n");
2773         if (listen(tcpsrfd, 15) < 0) {
2774             i = errno;                  /* Save error code */
2775 #ifdef TCPIPLIB
2776             socket_close(tcpsrfd);
2777 #else /* TCPIPLIB */
2778             close(tcpsrfd);
2779 #endif /* TCPIPLIB */
2780             tcpsrfd = -1;
2781             tcpsrv_port = 0;
2782             ttyfd = -1;
2783             wasclosed = 1;
2784             errno = i;                  /* And report this error */
2785             debug(F101,"tcpsrv_open listen errno","",errno);
2786             return(-1);
2787         }
2788         debug(F100,"tcpsrv_open listen OK","",0);
2789         tcpsrv_port = ntohs((unsigned short)service->s_port);
2790     }
2791
2792 #ifdef CK_SSL
2793     if (ck_ssleay_is_installed()) {
2794         if (!ssl_tn_init(SSL_SERVER)) {
2795             ssl_failed = 1;
2796             if (bio_err!=NULL) {
2797                 BIO_printf(bio_err,"do_ssleay_init() failed\n");
2798                 ERR_print_errors(bio_err);
2799             } else {
2800                 fflush(stderr);
2801                 fprintf(stderr,"do_ssleay_init() failed\n");
2802                 ERR_print_errors_fp(stderr);
2803             }
2804             if (tls_only_flag || ssl_only_flag) {
2805 #ifdef TCPIPLIB
2806                 socket_close(ttyfd);
2807                 socket_close(tcpsrfd);
2808 #else /* TCPIPLIB */
2809                 close(ttyfd);
2810                 close(tcpsrfd);
2811 #endif /* TCPIPLIB */
2812                 ttyfd = -1;
2813                 wasclosed = 1;
2814                 tcpsrfd = -1;
2815                 tcpsrv_port = 0;
2816                 return(-1);
2817             }
2818             /* we will continue to accept the connection   */
2819             /* without SSL or TLS support unless required. */
2820             if ( TELOPT_DEF_S_ME_MODE(TELOPT_START_TLS) != TN_NG_MU )
2821                 TELOPT_DEF_S_ME_MODE(TELOPT_START_TLS) = TN_NG_RF;
2822             if ( TELOPT_DEF_S_U_MODE(TELOPT_START_TLS) != TN_NG_MU )
2823                 TELOPT_DEF_S_U_MODE(TELOPT_START_TLS) = TN_NG_RF;
2824             if ( TELOPT_DEF_C_ME_MODE(TELOPT_START_TLS) != TN_NG_MU )
2825                 TELOPT_DEF_C_ME_MODE(TELOPT_START_TLS) = TN_NG_RF;
2826             if ( TELOPT_DEF_C_U_MODE(TELOPT_START_TLS) != TN_NG_MU )
2827                 TELOPT_DEF_C_U_MODE(TELOPT_START_TLS) = TN_NG_RF;
2828         }
2829     }
2830 #endif /* CK_SSL */
2831
2832     printf("\nWaiting to Accept a TCP/IP connection on port %d ...\n",
2833            ntohs((unsigned short)service->s_port));
2834     saddrlen = sizeof(saddr);
2835
2836 #ifdef BSDSELECT
2837     tv.tv_sec  = tv.tv_usec = 0L;
2838     if (timo < 0)
2839       tv.tv_usec = (long) -timo * 10000L;
2840     else
2841       tv.tv_sec = timo;
2842     debug(F101,"tcpsrv_open BSDSELECT","",timo);
2843 #else
2844     debug(F101,"tcpsrv_open not BSDSELECT","",timo);
2845 #endif /* BSDSELECT */
2846
2847     if (timo) {
2848         while (!ready_to_accept) {
2849 #ifdef BSDSELECT
2850             FD_ZERO(&rfds);
2851             FD_SET(tcpsrfd, &rfds);
2852             ready_to_accept =
2853               ((select(FD_SETSIZE,
2854 #ifdef HPUX
2855 #ifdef HPUX1010
2856                        (fd_set *)
2857 #else
2858
2859                        (int *)
2860 #endif /* HPUX1010 */
2861 #else
2862 #ifdef __DECC
2863 #ifdef INTSELECT
2864                        (int *)
2865 #else /* def INTSELECT */
2866                        (fd_set *)
2867 #endif /* def INTSELECT [else] */
2868 #endif /* __DECC */
2869 #endif /* HPUX */
2870                        &rfds, NULL, NULL, &tv) > 0) &&
2871                FD_ISSET(tcpsrfd, &rfds));
2872 #else /* BSDSELECT */
2873 #ifdef IBMSELECT
2874 #define ck_sleepint 250
2875             ready_to_accept =
2876               (select(&tcpsrfd, 1, 0, 0,
2877                       timo < 0 ? -timo :
2878                       (timo > 0 ? timo * 1000L : ck_sleepint)) == 1
2879                );
2880 #else
2881 #ifdef BELLSELECT
2882             FD_ZERO(rfds);
2883             FD_SET(tcpsrfd, rfds);
2884             ready_to_accept =
2885               ((select(128, rfds, NULL, NULL, timo < 0 ? -timo :
2886                       (timo > 0 ? timo * 1000L)) > 0) &&
2887                FD_ISSET(tcpsrfd, rfds));
2888 #else
2889 /* Try this - what's the worst that can happen... */
2890
2891             FD_ZERO(&rfds);
2892             FD_SET(tcpsrfd, &rfds);
2893             ready_to_accept =
2894               ((select(FD_SETSIZE,
2895                        (fd_set *) &rfds, NULL, NULL, &tv) > 0) &&
2896                FD_ISSET(tcpsrfd, &rfds));
2897
2898 #endif /* BELLSELECT */
2899 #endif /* IBMSELECT */
2900 #endif /* BSDSELECT */
2901         }
2902     }
2903     if (ready_to_accept || timo == 0) {
2904         if ((ttyfd = accept(tcpsrfd,
2905                             (struct sockaddr *)&saddr,&saddrlen)) < 0) {
2906             i = errno;                  /* save error code */
2907 #ifdef TCPIPLIB
2908             socket_close(tcpsrfd);
2909 #else /* TCPIPLIB */
2910             close(tcpsrfd);
2911 #endif /* TCPIPLIB */
2912             ttyfd = -1;
2913             wasclosed = 1;
2914             tcpsrfd = -1;
2915             tcpsrv_port = 0;
2916             errno = i;                  /* and report this error */
2917             debug(F101,"tcpsrv_open accept errno","",errno);
2918             return(-1);
2919         }
2920         setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
2921
2922 #ifndef NOTCPOPTS
2923 #ifndef datageneral
2924 #ifdef SOL_SOCKET
2925 #ifdef TCP_NODELAY
2926         no_delay(ttyfd,tcp_nodelay);
2927         debug(F101,"tcpsrv_open no_delay","",tcp_nodelay);
2928 #endif /* TCP_NODELAY */
2929 #ifdef SO_KEEPALIVE
2930         keepalive(ttyfd,tcp_keepalive);
2931         debug(F101,"tcpsrv_open keepalive","",tcp_keepalive);
2932 #endif /* SO_KEEPALIVE */
2933 #ifdef SO_LINGER
2934         ck_linger(ttyfd,tcp_linger, tcp_linger_tmo);
2935         debug(F101,"tcpsrv_open linger","",tcp_linger_tmo);
2936 #endif /* SO_LINGER */
2937 #ifdef SO_SNDBUF
2938         sendbuf(ttyfd,tcp_sendbuf);
2939 #endif /* SO_SNDBUF */
2940 #ifdef SO_RCVBUF
2941         recvbuf(ttyfd,tcp_recvbuf);
2942 #endif /* SO_RCVBUF */
2943 #endif /* SOL_SOCKET */
2944 #endif /* datageneral */
2945 #endif /* NOTCPOPTS */
2946
2947         ttnet = nett;                   /* TCP/IP (sockets) network */
2948         tcp_incoming = 1;               /* This is an incoming connection */
2949         sstelnet = 1;                   /* Do server-side Telnet protocol */
2950
2951         /* See if the service is TELNET. */
2952         x = (unsigned short)service->s_port;
2953         service2 = getservbyname("telnet", "tcp");
2954         if (service2 && x == service2->s_port) {
2955 #ifdef COMMENT
2956             /* Jeff 2005/12/30 */
2957             if (ttnproto != NP_TCPRAW && /* Yes... */
2958                  ttnproto != NP_SSL_RAW &&
2959                  ttnproto != NP_TLS_RAW) /* and if raw port not requested */
2960 #else
2961             /* fdc 2005/12/04 */
2962             if (ttnproto != NP_TCPRAW)  /* Yes and if raw port not requested */
2963 #endif  /*  */
2964               ttnproto = NP_TELNET;     /* set protocol to TELNET. */
2965         }
2966         ckstrncpy(ipaddr,(char *)inet_ntoa(saddr.sin_addr),20);
2967         if (tcp_rdns) {
2968             if (!quiet) {
2969                 printf(" Reverse DNS Lookup... ");
2970                 fflush(stdout);
2971             }
2972             if (host = gethostbyaddr((char *)&saddr.sin_addr,4,PF_INET)) {
2973                 host = ck_copyhostent(host);
2974                 debug(F100,"tcpsrv_open gethostbyaddr != NULL","",0);
2975                 if (!quiet) {
2976                     printf("(OK)\n");
2977                     fflush(stdout);
2978                 }
2979                 name[0] = '*';
2980                 ckstrncpy(&name[1],host->h_name,78);
2981                 ckstrncat(name,":",80-strlen(name));
2982                 ckstrncat(name,p,80-strlen(name));
2983                 if (!quiet
2984 #ifndef NOICP
2985                     && !doconx
2986 #endif /* NOICP */
2987                     )
2988                   printf("%s connected on port %s\n",host->h_name,p);
2989             } else {
2990                 if (!quiet) printf("Failed.\n");
2991             }
2992         } else if (!quiet) printf("(OK)\n");
2993
2994         if (!tcp_rdns || !host) {
2995             ckstrncpy(name,ipaddr,80);
2996             ckstrncat(name,":",80);
2997             ckstrncat(name,ckuitoa(ntohs(saddr.sin_port)),80);
2998             if (!quiet
2999 #ifndef NOICP
3000                 && !doconx
3001 #endif /* NOICP */
3002                 )
3003               printf("%s connected on port %d\n",ipaddr,ntohs(saddr.sin_port));
3004         }
3005         if (!quiet) fflush(stdout);
3006
3007 #ifdef CK_SECURITY
3008         /* Before Initialization Telnet/Rlogin Negotiations Init Kerberos */
3009         ck_auth_init((tcp_rdns && host && host->h_name && host->h_name[0]) ?
3010                      (char *)host->h_name : ipaddr,
3011                      ipaddr,
3012                      uidbuf,
3013                      ttyfd
3014                      );
3015 #endif /* CK_SECURITY */
3016
3017 #ifdef CK_SSL
3018         if (ck_ssleay_is_installed() && !ssl_failed) {
3019             if (ck_ssl_incoming(ttyfd) < 0) {
3020 #ifdef TCPIPLIB
3021                     socket_close(ttyfd);
3022                     socket_close(tcpsrfd);
3023 #else /* TCPIPLIB */
3024                     close(ttyfd);
3025                     close(tcpsrfd);
3026 #endif /* TCPIPLIB */
3027                     ttyfd = -1;
3028                     wasclosed = 1;
3029                     tcpsrfd = -1;
3030                     tcpsrv_port = 0;
3031                     return(-1);
3032             }
3033         }
3034 #endif /* CK_SSL */
3035
3036 #ifndef datageneral
3037         /* Find out our own IP address. */
3038         l_slen = sizeof(l_addr);
3039         bzero((char *)&l_addr, l_slen);
3040 #ifndef EXCELAN
3041         if (!getsockname(ttyfd, (struct sockaddr *)&l_addr, &l_slen)) {
3042             char * s = (char *)inet_ntoa(l_addr.sin_addr);
3043             ckstrncpy(myipaddr, s,20);
3044             debug(F110,"getsockname",myipaddr,0);
3045         }
3046 #endif /* EXCELAN */
3047 #endif /* datageneral */
3048
3049         if (tn_ini() < 0)               /* Start TELNET negotiations. */
3050           if (ttchk() < 0) {            /* Disconnected? */
3051               i = errno;                /* save error code */
3052 #ifdef TCPIPLIB
3053               socket_close(tcpsrfd);
3054 #else /* TCPIPLIB */
3055               close(tcpsrfd);
3056 #endif /* TCPIPLIB */
3057               ttyfd = -1;
3058               wasclosed = 1;
3059               tcpsrfd = -1;
3060               tcpsrv_port = 0;
3061               errno = i;                /* and report this error */
3062               debug(F101,"tcpsrv_open accept errno","",errno);
3063               return(-1);
3064           }
3065         debug(F101,"tcpsrv_open service","",x);
3066         if (*lcl < 0)                   /* Set local mode. */
3067           *lcl = 1;
3068
3069 #ifdef CK_KERBEROS
3070 #ifdef KRB5_U2U
3071         if ( ttnproto == NP_K5U2U ) {
3072             if (k5_user_to_user_server_auth() != 0) {
3073                 i = errno;                /* save error code */
3074 #ifdef TCPIPLIB
3075                 socket_close(tcpsrfd);
3076 #else /* TCPIPLIB */
3077                 close(tcpsrfd);
3078 #endif /* TCPIPLIB */
3079                 ttyfd = -1;
3080                 wasclosed = 1;
3081                 tcpsrfd = -1;
3082                 tcpsrv_port = 0;
3083                 errno = i;                /* and report this error */
3084                 debug(F101,"tcpsrv_open accept errno","",errno);
3085                 return(-1);
3086             }
3087         }
3088 #endif /* KRB5_U2U */
3089 #endif /* CK_KERBEROS */
3090         return(0);                      /* Done. */
3091     } else {
3092         i = errno;                      /* save error code */
3093 #ifdef TCPIPLIB
3094         socket_close(tcpsrfd);
3095 #else /* TCPIPLIB */
3096         close(tcpsrfd);
3097 #endif /* TCPIPLIB */
3098         ttyfd = -1;
3099         wasclosed = 1;
3100         tcpsrfd = -1;
3101         tcpsrv_port = 0;
3102         errno = i;                      /* and report this error */
3103         debug(F101,"tcpsrv_open accept errno","",errno);
3104         return(-1);
3105     }
3106 }
3107 #endif /* NOLISTEN */
3108 #endif /* OS2 */
3109 #endif /* TCPSOCKET */
3110 #endif /* NONET */
3111
3112 #ifdef TCPSOCKET
3113 char *
3114 ckname2addr(name) char * name;
3115 {
3116 #ifdef HPUX5
3117     return("");
3118 #else
3119     struct hostent *host;
3120
3121     if (name == NULL || *name == '\0')
3122         return("");
3123
3124     host = gethostbyname(name);
3125     if ( host ) {
3126         host = ck_copyhostent(host);
3127         return(inet_ntoa(*((struct in_addr *) host->h_addr)));
3128     }
3129     return("");
3130 #endif /* HPUX5 */
3131 }
3132
3133 char *
3134 ckaddr2name(addr) char * addr;
3135 {
3136 #ifdef HPUX5
3137     return("");
3138 #else
3139     struct hostent *host;
3140     struct in_addr sin_addr;
3141
3142     if (addr == NULL || *addr == '\0')
3143         return("");
3144
3145     sin_addr.s_addr = inet_addr(addr);
3146     host = gethostbyaddr((char *)&sin_addr,4,AF_INET);
3147     if (host) {
3148         host = ck_copyhostent(host);
3149         return((char *)host->h_name);
3150     }
3151     return("");
3152 #endif /* HPUX5 */
3153 }
3154 #endif /* TCPSOCKET */
3155
3156 unsigned long peerxipaddr = 0L;
3157
3158 char *
3159 ckgetpeer() {
3160 #ifdef TCPSOCKET
3161     static char namebuf[256];
3162     static struct hostent *host;
3163     static struct sockaddr_in saddr;
3164 #ifdef GPEERNAME_T
3165     static GPEERNAME_T saddrlen;
3166 #else
3167 #ifdef PTX
3168     static size_t saddrlen;
3169 #else
3170 #ifdef AIX42
3171     /* It's size_t in 4.2 but int in 4.1 and earlier. */
3172     /* Note: the 4.2 man page lies; believe socket.h. */
3173     static size_t saddrlen;
3174 #else
3175 #ifdef UNIXWARE
3176     static size_t saddrlen;
3177 #else  /* UNIXWARE */
3178 #ifdef DEC_TCPIP
3179 /* 2010-03-08 SMS.
3180  * Coincidentally, the condition for integer arguments in select(),
3181  * which is actually "defined( _DECC_V4_SOURCE)", works for an integer
3182  * argument in getpeername().  Sadly, due to a lack of foresight,
3183  * "defined( _DECC_V4_SOURCE)" doesn't work with DEC C V4.0, so the
3184  * user-specified INTSELECT is used instead.  Most likely, "size_t"
3185  * should be used instead of "unsigned int", but I'm a coward.
3186  */
3187 #ifdef INTSELECT
3188     static int saddrlen;
3189 #else /* def INTSELECT */
3190     static unsigned int saddrlen;
3191 #endif /* def INTSELECT [else] */
3192 #else
3193 #ifdef MACOSX10
3194     static unsigned int saddrlen;
3195 #else
3196 #ifdef CK_64BIT
3197     static socklen_t saddrlen;
3198 #else
3199     static int saddrlen;
3200 #endif  /* CK_64BIT */
3201 #endif /* MACOSX10 */
3202 #endif /* DEC_TCPIP */
3203 #endif /* UNIXWARE */
3204 #endif /* AIX42 */
3205 #endif /* PTX */
3206 #endif  /* GPEERNAME_T */
3207     saddrlen = sizeof(saddr);
3208     if (getpeername(ttyfd,(struct sockaddr *)&saddr,&saddrlen) < 0) {
3209         debug(F111,"ckgetpeer failure",ckitoa(ttyfd),errno);
3210         return(NULL);
3211     }
3212     host = gethostbyaddr((char *)&saddr.sin_addr,4,AF_INET);
3213     if (host) {
3214         host = ck_copyhostent(host);
3215         ckstrncpy(namebuf,(char *)host->h_name,80);
3216     } else {
3217         ckstrncpy(namebuf,(char *)inet_ntoa(saddr.sin_addr),80);
3218     }
3219     peerxipaddr = ntohl(saddr.sin_addr.s_addr);
3220     debug(F111,"ckgetpeer",namebuf,peerxipaddr);
3221     return(namebuf);
3222 #else
3223     return(NULL);
3224 #endif /* TCPSOCKET */
3225 }
3226
3227 /* Get fully qualified IP hostname */
3228
3229 #ifndef NONET
3230 char *
3231 #ifdef CK_ANSIC
3232 ckgetfqhostname(char * name)
3233 #else
3234 ckgetfqhostname(name) char * name;
3235 #endif /* CK_ANSIC */
3236 {
3237 #ifdef NOCKGETFQHOST
3238
3239     return(name);
3240
3241 #else /* If the following code dumps core, define NOCKGETFQHOST and rebuild. */
3242
3243     static char namebuf[256];
3244     struct hostent *host=NULL;
3245     struct sockaddr_in r_addr;
3246     int i;
3247
3248     debug(F110,"ckgetfqhn()",name,0);
3249
3250     ckstrncpy(namebuf,name,256);
3251     namebuf[255] = '\0';
3252     i = ckindex(":",namebuf,0,0,0);
3253     if (i)
3254       namebuf[i-1] = '\0';
3255
3256     bzero((char *)&r_addr, sizeof(r_addr));
3257
3258     host = gethostbyname(namebuf);
3259     if (host) {
3260         host = ck_copyhostent(host);
3261         debug(F100,"ckgetfqhn() gethostbyname != NULL","",0);
3262         r_addr.sin_family = host->h_addrtype;
3263 #ifdef HADDRLIST
3264 #ifdef h_addr
3265         /* This is for trying multiple IP addresses - see <netdb.h> */
3266         if (!(host->h_addr_list))
3267           goto exit_func;
3268         bcopy(host->h_addr_list[0],
3269               (caddr_t)&r_addr.sin_addr,
3270               host->h_length
3271               );
3272 #else
3273         bcopy(host->h_addr, (caddr_t)&r_addr.sin_addr, host->h_length);
3274 #endif /* h_addr */
3275 #else  /* HADDRLIST */
3276         bcopy(host->h_addr, (caddr_t)&r_addr.sin_addr, host->h_length);
3277 #endif /* HADDRLIST */
3278 #ifdef COMMENT
3279 #ifndef EXCELAN
3280         debug(F111,"BCOPY","host->h_addr",host->h_addr);
3281 #endif /* EXCELAN */
3282         debug(F111,"BCOPY"," (caddr_t)&r_addr.sin_addr",
3283               (caddr_t)&r_addr.sin_addr);
3284 #endif  /* COMMENT */
3285         debug(F111,"BCOPY","host->h_length",host->h_length);
3286
3287 #ifdef NT
3288         /* Windows 95/98 requires a 1 second wait between calls to Microsoft */
3289         /* provided DNS functions.  Otherwise, the TTL of the DNS response */
3290         /* is ignored. */
3291         if (isWin95())
3292           sleep(1);
3293 #endif /* NT */
3294         host = gethostbyaddr((char *)&r_addr.sin_addr,4,PF_INET);
3295         if (host) {
3296             host = ck_copyhostent(host);
3297             debug(F100,"ckgetfqhn() gethostbyaddr != NULL","",0);
3298             ckstrncpy(namebuf, host->h_name, 256);
3299         }
3300     }
3301
3302 #ifdef HADDRLIST
3303 #ifdef h_addr
3304   exit_func:
3305 #endif /* h_addr */
3306 #endif /* HADDRLIST */
3307
3308     if (i > 0)
3309       ckstrncat(namebuf,&name[i-1],256-strlen(namebuf)-strlen(&name[i-1]));
3310     debug(F110,"ckgetfqhn()",namebuf,0);
3311     return(namebuf);
3312 #endif /* NOCKGETFQHOST */
3313 }
3314
3315 VOID
3316 #ifdef CK_ANSIC
3317 setnproto(char * p)
3318 #else
3319 setnproto(p) char * p;
3320 #endif /* CK_ANSIC */
3321 {
3322     if (!isdigit(*p)) {
3323         if (!strcmp("kermit",p))
3324           ttnproto = NP_KERMIT;
3325         else if (!strcmp("telnet",p))
3326           ttnproto = NP_TELNET;
3327         else if (!strcmp("http",p))
3328           ttnproto = NP_TCPRAW;
3329 #ifdef RLOGCODE
3330         else if (!strcmp("login",p))
3331           ttnproto = NP_RLOGIN;
3332 #endif /* RLOGCODE */
3333 #ifdef CK_SSL
3334         /* Commonly used SSL ports (might not be in services file) */
3335         else if (!strcmp("https",p)) {
3336           ttnproto = NP_SSL_RAW;
3337           ssl_only_flag = 1;
3338         } else if (!strcmp("ssl-telnet",p)) {
3339           ttnproto = NP_TELNET;
3340           ssl_only_flag = 1;
3341         } else if (!strcmp("telnets",p)) {
3342           ttnproto = NP_TELNET;
3343           ssl_only_flag = 1;
3344         }
3345 #endif /* CK_SSL */
3346 #ifdef CK_KERBEROS
3347 #ifdef RLOGCODE
3348         else if (!strcmp("klogin",p)) {
3349             if (ck_krb5_is_installed())
3350               ttnproto = NP_K5LOGIN;
3351             else if (ck_krb4_is_installed())
3352               ttnproto = NP_K4LOGIN;
3353             else
3354               ttnproto = NP_RLOGIN;
3355         } else if (!strcmp("eklogin",p)) {
3356             if (ck_krb5_is_installed())
3357               ttnproto = NP_EK5LOGIN;
3358             else if (ck_krb4_is_installed())
3359               ttnproto = NP_EK4LOGIN;
3360             else
3361               ttnproto = NP_RLOGIN;
3362         }
3363 #endif /* RLOGCODE */
3364 #endif /* CK_KERBEROS */
3365         else
3366           ttnproto = NP_NONE;
3367     } else {
3368         switch (atoi(p)) {
3369           case 23:                      /* Telnet */
3370             ttnproto = NP_TELNET;
3371             break;
3372           case 513:
3373             ttnproto = NP_RLOGIN;
3374             break;
3375           case 1649:
3376             ttnproto = NP_KERMIT;
3377             break;
3378 #ifdef CK_SSL
3379           case 443:
3380 #ifdef COMMENT
3381             /* Jeff 2005/12/30 */
3382             ttnproto = NP_SSL_RAW;
3383 #else
3384             /* fdc 2005/12/04 */
3385             ttnproto = NP_SSL;
3386 #endif  /* COMMENT */
3387             ssl_only_flag = 1;
3388             break;
3389           case 151:
3390           case 992:
3391             ttnproto = NP_TELNET;
3392             ssl_only_flag = 1;
3393             break;
3394 #endif /* CK_SSL */
3395 #ifdef CK_KERBEROS
3396           case 543:
3397             if (ck_krb5_is_installed())
3398               ttnproto = NP_K5LOGIN;
3399             else if (ck_krb4_is_installed())
3400               ttnproto = NP_K4LOGIN;
3401             else
3402               ttnproto = NP_RLOGIN;
3403             break;
3404           case 2105:
3405             if (ck_krb5_is_installed())
3406               ttnproto = NP_EK5LOGIN;
3407             else if (ck_krb4_is_installed())
3408               ttnproto = NP_EK4LOGIN;
3409             else
3410               ttnproto = NP_RLOGIN;
3411             break;
3412 #endif /* CK_KERBEROS */
3413           case 80:                      /* HTTP */
3414             ttnproto = NP_TCPRAW;
3415             break;
3416           default:
3417             ttnproto = NP_NONE;
3418             break;
3419         }
3420     }
3421 }
3422
3423 /* ckgetservice() is used to determine the port number for a given */
3424 /* service taking into account the use of DNS SRV records.         */
3425
3426 static struct servent servrec;
3427 static struct servent *
3428 ckgetservice(hostname, servicename, ip, iplen)
3429     char *hostname; char * servicename; char * ip; int iplen;
3430 {
3431     struct servent * service = NULL;
3432 #ifdef CK_DNS_SRV
3433     struct sockaddr * dns_addrs = NULL;
3434     int dns_naddrs = 0;
3435 #endif /* CK_DNS_SRV */
3436
3437     if (isdigit(*servicename)) {        /* Use socket number without lookup */
3438         service = &servrec;
3439         service->s_port = htons((unsigned short)atoi(servicename));
3440     } else {                            /* Otherwise lookup the service name */
3441 #ifdef CK_DNS_SRV
3442         if (tcp_dns_srv && !quiet) {
3443             printf(" DNS SRV Lookup... ");
3444             fflush(stdout);
3445         }
3446         if (tcp_dns_srv &&
3447             locate_srv_dns(hostname,
3448                            servicename,
3449                            "tcp",
3450                            &dns_addrs,
3451                            &dns_naddrs
3452                            )
3453             ) {
3454             /* Use the first one.  Eventually we should cycle through all */
3455             /* the returned IP addresses and port numbers. */
3456             struct sockaddr_in *sin = NULL;
3457 #ifdef BETADEBUG
3458             int i;
3459             printf("\r\n");
3460             for ( i=0;i<dns_naddrs;i++ ) {
3461                 sin = (struct sockaddr_in *) &dns_addrs[i];
3462                 printf("dns_addrs[%d] = %s %d\r\n", i,
3463                         (char *)inet_ntoa(sin->sin_addr),
3464                         ntohs(sin->sin_port));
3465             }
3466 #endif /* BETADEBUG */
3467             sin = (struct sockaddr_in *) &dns_addrs[0];
3468             if ( ip && iplen > 0 )
3469                 ckstrncpy(ip,(char *)inet_ntoa(sin->sin_addr),iplen);
3470             service = &servrec;
3471             service->s_port = sin->sin_port;
3472
3473             free(dns_addrs);
3474             dns_addrs = NULL;
3475             dns_naddrs = 0;
3476         } else
3477 #endif /* CK_DNS_SRV */
3478             service = getservbyname(servicename, "tcp");
3479     }
3480     if (!service) {
3481         if (!ckstrcmp("kermit",servicename,-1,0)) { /* Kermit service port */
3482             service = &servrec;
3483             service->s_port = htons(1649);
3484         } else if (!ckstrcmp("telnet",servicename,-1,0)) { /* Telnet port */
3485             service = &servrec;
3486             service->s_port = htons(23);
3487         } else if (!ckstrcmp("http",servicename,-1,0)) {
3488             service = &servrec;
3489             service->s_port = htons(80);
3490         }
3491 #ifdef RLOGCODE
3492         else if (!ckstrcmp("login",servicename,-1,0)) {
3493             service = &servrec;
3494             service->s_port = htons(513);
3495         }
3496 #endif /* RLOGCODE */
3497 #ifdef CK_SSL
3498         /* Commonly used SSL ports (might not be in services file) */
3499         else if (!ckstrcmp("https",servicename,-1,0)) {
3500             service = &servrec;
3501             service->s_port = htons(443);
3502         } else if (!ckstrcmp("ssl-telnet",servicename,-1,0)) {
3503             service = &servrec;
3504             service->s_port = htons(151);
3505         } else if (!ckstrcmp("telnets",servicename,-1,0)) {
3506             service = &servrec;
3507             service->s_port = htons(992);
3508         }
3509 #endif /* CK_SSL */
3510 #ifdef CK_KERBEROS
3511 #ifdef RLOGCODE
3512         else if (!ckstrcmp("klogin",servicename,-1,0)) {
3513             service = &servrec;
3514             service->s_port = htons(543);
3515         } else if (!ckstrcmp("eklogin",servicename,-1,0)) {
3516             service = &servrec;
3517             service->s_port = htons(2105);
3518         }
3519 #endif /* RLOGCODE */
3520 #endif /* CK_KERBEROS */
3521     }
3522     return(service);
3523 }
3524
3525 /*  N E T O P E N  --  Open a network connection  */
3526 /*
3527   Calling conventions same as ttopen(), except third argument is network
3528   type rather than modem type.  Designed to be called from within ttopen.
3529 */
3530
3531 #define XXNAMELEN 256
3532 static char xxname[XXNAMELEN];
3533
3534 int
3535 netopen(name, lcl, nett) char *name; int *lcl, nett; {
3536     char *p;
3537     int i, x, rc_inet_addr = 0, dns = 0;
3538 #ifdef TCPSOCKET
3539     int isconnect = 0;
3540 #ifdef SO_OOBINLINE
3541     int on = 1;
3542 #endif /* SO_OOBINLINE */
3543     struct servent *service=NULL;
3544     struct hostent *host=NULL;
3545     struct sockaddr_in r_addr;
3546     struct sockaddr_in sin;
3547     struct sockaddr_in l_addr;
3548     GSOCKNAME_T l_slen;
3549 #ifdef EXCELAN
3550     struct sockaddr_in send_socket;
3551 #endif /* EXCELAN */
3552
3553 #ifdef INADDRX
3554 /* inet_addr() is of type struct in_addr */
3555 #ifdef datageneral
3556     extern struct in_addr inet_addr();
3557 #else
3558 #ifdef HPUX5WINTCP
3559     extern struct in_addr inet_addr();
3560 #endif /* HPUX5WINTCP */
3561 #endif /* datageneral */
3562     struct in_addr iax;
3563 #else
3564 #ifdef INADDR_NONE
3565     struct in_addr iax;
3566 #else /* INADDR_NONE */
3567     long iax;
3568 #endif /* INADDR_NONE */
3569 #endif /* INADDRX */
3570 #endif /* TCPSOCKET */
3571
3572 #ifdef COMMENT
3573 /* This causes big trouble */
3574 #ifndef INADDR_NONE
3575 #define INADDR_NONE 0xffffffff
3576 #endif /* INADDR_NONE */
3577 #endif /* COMMENT */
3578
3579 #ifdef SUNX25                           /* Code for SunLink X.25 support */
3580 #define X29PID 1                        /* X.29 Protocol ID */
3581 _PROTOTYP(SIGTYP x25oobh, (int) );
3582     CONN_DB x25host;
3583 #ifndef X25_WR_FACILITY
3584     FACILITY x25facil;
3585 #else
3586     FACILITY_DB x25facil;
3587 #endif /* X25_WR_FACILITY */
3588     static int needh = 1;
3589     PID_T pid;
3590     extern int linkid, lcn, x25ver;
3591 #endif /* SUNX25 */
3592 #ifdef ANYX25
3593     extern int revcall, closgr, cudata;
3594     extern char udata[];
3595 #endif /* ANYX25 */
3596
3597 #ifdef IBMX25                           /* Variables for IBM X25 */
3598     extern int x25port;                 /* Logical port to use */
3599     extern x25addr_t local_nua;         /* Local X.25 address */
3600     extern x25addr_t remote_nua;        /* Remote X.25 address */
3601     extern char x25name[];              /* X25 device name (sx25a0) */
3602     extern char x25dev[];               /* X25 device file /dev/x25pkt */
3603     ulong bind_flags = 0;               /* Flags for binding the X25 stream */
3604     ulong token = 0;                    /* Temporary return code */
3605 #endif /* IBMX25 */
3606
3607     debug(F101,"netopen nett","",nett);
3608     *ipaddr = '\0';                     /* Initialize IP address string */
3609
3610 #ifdef SUNX25
3611     if (nett == NET_SX25) {             /* If network type is X.25 */
3612         netclos();                      /* Close any previous net connection */
3613         ttnproto = NP_NONE;             /* No protocol selected yet */
3614
3615         /* Set up host structure */
3616         bzero((char *)&x25host,sizeof(x25host));
3617         if ((x25host.hostlen = pkx121(name,x25host.host)) < 0) {
3618             fprintf (stderr,"Invalid X.121 host address %s\n",name);
3619             errno = 0;
3620             return (-1);
3621         }
3622         x25host.datalen = X29PIDLEN;
3623         x25host.data[0] = X29PID;
3624
3625         /* Set call user data if specified */
3626         if (cudata) {
3627             ckstrncpy((char *)x25host.data+X29PIDLEN,udata,(int)strlen(udata));
3628             x25host.datalen += (int)strlen(udata);
3629         }
3630
3631         /* Open SunLink X.25 socket */
3632         if (!quiet && *name) {
3633             printf(" Trying %s... ", name);
3634             fflush(stdout);
3635         }
3636         if ((ttyfd = socket(AF_X25, SOCK_STREAM, 0)) < 0) {
3637             debug(F101,"netopen socket error","",errno);
3638             perror ("X.25 socket error");
3639             return (-1);
3640         }
3641
3642         /* Setting X.25 out-of-band data handler */
3643         pid = getpid();
3644         if (ioctl(ttyfd,SIOCSPGRP,&pid)) {
3645             perror("X.25 set process group id error");
3646             return(-1);
3647         }
3648         (VOID) signal(SIGURG,x25oobh);
3649
3650         /* Set reverse charge call and closed user group if requested */
3651         bzero ((char *)&x25facil,sizeof(x25facil));
3652
3653 #ifndef X25_WR_FACILITY
3654 /*  New SunLink (7.0 or 8.0, not sure which)... */
3655         x25facil.type = T_REVERSE_CHARGE; /* Reverse Charge */
3656         x25facil.f_reverse_charge = revcall ? 1 : 0;
3657         if (ioctl(ttyfd,X25_SET_FACILITY,&x25facil) < 0) {
3658             perror ("Setting X.25 reverse charge");
3659             return (-1);
3660         }
3661         if (closgr > -1) {              /* Closed User Group (Outgoing) */
3662             bzero ((char *)&x25facil,sizeof(x25facil));
3663             x25facil.type = T_CUG;
3664             x25facil.f_cug_req = CUG_REQ_ACS;
3665             x25facil.f_cug_index = closgr;
3666             if (ioctl(ttyfd,X25_SET_FACILITY,&x25facil) < 0) {
3667                 perror ("Setting X.25 closed user group");
3668                 return (-1);
3669             }
3670         }
3671 #else
3672 /*  Old SunLink 6.0 (or 7.0?)... */
3673         if (revcall) x25facil.reverse_charge = revcall;
3674         if (closgr > -1) {
3675             x25facil.cug_req = 1;
3676             x25facil.cug_index = closgr;
3677         }
3678         if (ioctl(ttyfd,X25_WR_FACILITY,&x25facil) < 0) {
3679             perror ("Setting X.25 facilities");
3680             return (-1);
3681         }
3682 #endif /* X25_WR_FACILITY */
3683
3684         /*  Need X.25 header with bits Q and M */
3685         if (ioctl (ttyfd,X25_HEADER,&needh) < 0) {
3686             perror ("Setting X.25 header");
3687             return (-1);
3688         }
3689
3690         /* Connects to remote host via SunLink X.25 */
3691         if (connect(ttyfd,(struct sockaddr *)&x25host,sizeof(x25host)) < 0) {
3692             i = errno;
3693             debug(F101,"netopen connect errno","",i);
3694             if (i) {
3695                 perror("netopen x25 connect");
3696                 x25diag();
3697             }
3698             (VOID) netclos();
3699             ttyfd = -1;
3700             wasclosed = 1;
3701             ttnproto = NP_NONE;
3702             errno = i;
3703             return (-1);
3704         }
3705
3706         /* Get X.25 link identification used for the connection */
3707         if (ioctl(ttyfd,X25_GET_LINK,&linkid) < 0) {
3708             perror ("Getting X.25 link id");
3709             return (-1);
3710         }
3711
3712         /* Get X.25 logical channel number used for the connection */
3713         if (ioctl(ttyfd,X25_RD_LCGN,&lcn) < 0) {
3714             perror ("Getting X.25 lcn");
3715             return (-1);
3716         }
3717
3718         /* Get SunLink X.25 version */
3719         if (ioctl(ttyfd,X25_VERSION,&x25ver) < 0) {
3720             perror ("Getting SunLink X.25 version");
3721             return (-1);
3722         }
3723         ttnet = nett;                   /* Sunlink X.25 network */
3724         ttnproto = NP_X3;               /* PAD X.3, X.28, X.29 protocol */
3725         if (lcl) if (*lcl < 0) *lcl = 1; /* Local mode */
3726         return(0);
3727     } else /* Note that SUNX25 support can coexist with TCP/IP support. */
3728 #endif /* SUNX25 */
3729
3730 #ifdef IBMX25
3731     /* riehm */
3732     if (nett == NET_IX25) {             /* IBM AIX X.25 */
3733         netclos();                      /* Close any previous net connection */
3734         ttnproto = NP_NONE;             /* No protocol selected yet */
3735
3736         /* find out who we are - this is not so easy on AIX */
3737         /* riehm: need to write the code that finds this out
3738          * automatically, or at least allow it to be configured
3739          * somehow
3740          */
3741         if (!local_nua[0] && !x25local_nua(local_nua)) {
3742             return(-1);
3743         }
3744
3745         /* Initialise the X25 API (once per process? once per connection?) */
3746
3747         debug(F110, "Opening ", x25dev, 0 );
3748         /* set O_NDELAY to allow polling? */
3749         if ((ttyfd = open(x25dev, O_RDWR)) < 0) {
3750             perror ("X.25 device open error");
3751             debug(F101,"netopen: device open error","",errno);
3752             return (-1);
3753         }
3754
3755         /* push the NPI onto the STREAM */
3756         if (ioctl(ttyfd,I_PUSH,"npi") < 0 ) {
3757             close(ttyfd);
3758             ttyfd = -1;
3759             wasclosed = 1;
3760             perror( "kermit: netopen(): couldn't push npi on the X25 stream" );
3761             debug(F101,"netopen: can't push npi on the X25 stream","",errno);
3762             return (-1);
3763         }
3764
3765         /* set up server mode - bind the x25 port and wait for
3766          * incoming connections
3767          */
3768         if (name[0] == '*') {           /* Server */
3769             /* set up a server - see the warning in x25bind() */
3770             bind_flags |= TOKEN_REQUEST;
3771
3772             /* bind kermit to the local X25 address */
3773             token = x25bind(ttyfd,
3774                             local_nua,
3775                             udata,
3776                             (int)strlen( udata ),
3777                             1,
3778                             x25port,
3779                             bind_flags
3780                             );
3781             if (token < 0) {
3782                 debug(F100,"netopen: couldn't bind to local X25 address","",0);
3783                 netclos();
3784                 return(-1);
3785             }
3786             /* Currently not connected to a remote host */
3787
3788             remote_nua[0] = '\0';
3789
3790             /* store the fd so that incoming calls can have their own fd
3791              * This is almost support for a true server (ie: a'la ftpd)
3792              * but we're not quite there yet.
3793              * used in netclos()
3794              */
3795             x25serverfd = ttyfd;
3796             /*
3797              * wait for an incoming call
3798              * this should happen in the "server" command and not in
3799              * the "set host *" command.
3800              */
3801             if ((ttyfd = x25getcall(ttyfd)) < 0) {
3802                 netclos();
3803                 return(-1);
3804             }
3805         } else {                        /* Client */
3806             /* Bind kermit to the local X25 address */
3807             token = x25bind(
3808                             ttyfd,
3809                             local_nua,
3810                             (char *)NULL,
3811                             0,
3812                             0,
3813                             x25port,
3814                             bind_flags
3815                             );
3816             if (token < 0) {
3817                 debug(F100,"netopen: couldn't bind to local X25 address","",0);
3818                 netclos();
3819                 return(-1);
3820             }
3821 /* riehm: this should be done via the CONNECT command, not HOST! */
3822             {
3823                 x25serverfd = 0;
3824                 /* call the remote host */
3825                 /* name == address of remote host as char* */
3826                 if (x25call(ttyfd, name, udata) < 0 ) {
3827                     debug(F100,
3828                           "netopen: couldn't connect to remote X25 address",
3829                           "", 0);
3830                     netclos();
3831                     return(-1);
3832                 }
3833                 strcpy(remote_nua, name);
3834             }
3835         }
3836         ttnet = nett;                   /* AIX X.25 network */
3837         if (lcl) if (*lcl < 0) *lcl = 1; /* Local mode */
3838         return(0);
3839
3840     } else /* Note that IBMX25 support can coexist with TCP/IP support. */
3841 #endif /* IBMX25 */
3842
3843 /*   Add support for other networks here. */
3844
3845       if (nett != NET_TCPB) return(-1); /* BSD socket support */
3846
3847 #ifdef TCPSOCKET
3848     netclos();                          /* Close any previous connection. */
3849     ckstrncpy(namecopy, name, NAMECPYL);        /* Copy the hostname. */
3850     debug(F110,"netopen namecopy",namecopy,0);
3851
3852 #ifndef NOLISTEN
3853     if (name[0] == '*')
3854       return(tcpsrv_open(name, lcl, nett, 0));
3855 #endif /* NOLISTEN */
3856
3857     p = namecopy;                       /* Was a service requested? */
3858     while (*p != '\0' && *p != ':') p++; /* Look for colon */
3859     if (*p == ':') {                    /* Have a colon */
3860         debug(F110,"netopen name has colon",namecopy,0);
3861         *p++ = '\0';                    /* Get service name or number */
3862 #ifdef CK_URL
3863         /*
3864            Here we have to check for various popular syntaxes:
3865            host:port (our original syntax)
3866            URL such as telnet:host or telnet://host/
3867            Or even telnet://user:password@host:port/path/
3868            Or a malformed URL such as generated by Netscape 4.0 like:
3869            telnet:telnet or telnet::host.
3870         */
3871
3872         /*
3873          * REPLACE THIS CODE WITH urlparse() but not on the day of the
3874          * C-Kermit 8.0 RELEASE.
3875          */
3876
3877         if (*p == ':')                  /* a second colon */
3878           *p++ = '\0';                  /* get rid of that one too */
3879         while (*p == '/') *p++ = '\0';  /* and slashes */
3880         x = strlen(p);                  /* Length of remainder */
3881         if (p[x-1] == '/')              /* If there is a trailing slash */
3882           p[x-1] = '\0';                /* remove it. */
3883         debug(F110,"netopen namecopy after stripping",namecopy,0);
3884         debug(F110,"netopen p after stripping",p,0);
3885         service = getservbyname(namecopy,"tcp");
3886         if (service ||
3887 #ifdef RLOGCODE
3888             !ckstrcmp("rlogin",namecopy,NAMECPYL,0) ||
3889 #endif /* RLOGCODE */
3890 #ifdef CK_SSL
3891             !ckstrcmp("telnets",namecopy,NAMECPYL,0) ||
3892 #endif /* CK_SSL */
3893             !ckstrcmp("iksd",namecopy,NAMECPYL,0)
3894             ) {
3895             char temphost[256], tempservice[80], temppath[256];
3896             char * q = p, *r = p, *w = p;
3897             int uidfound=0;
3898             extern char pwbuf[];
3899             extern int pwflg, pwcrypt;
3900
3901             if (ttnproto == NP_DEFAULT)
3902               setnproto(namecopy);
3903
3904             /* Check for userid and possibly password */
3905             while (*p != '\0' && *p != '@')
3906                 p++; /* look for @ */
3907             if (*p == '@') {
3908                 /* found username and perhaps password */
3909                 debug(F110,"netopen namecopy found @","",0);
3910                 *p = '\0';
3911                 p++;
3912                 while (*w != '\0' && *w != ':')
3913                   w++;
3914                 if (*w == ':')
3915                   *w++ = '\0';
3916                 /* r now points to username, save it and the password */
3917                 debug(F110,"netopen namecopy username",r,0);
3918                 debug(F110,"netopen namecopy password",w,0);
3919                 uidfound=1;
3920                 if ( strcmp(uidbuf,r) || *w )
3921                     ckstrncpy(pwbuf,w,PWBUFL+1);
3922                 ckstrncpy(uidbuf,r,UIDBUFLEN);
3923                 pwflg = 1;
3924                 pwcrypt = 0;
3925                 q = p;                  /* Host after user and pwd */
3926             } else {
3927                 p = q;                  /* No username or password */
3928             }
3929             /* Now we must look for the optional port. */
3930             debug(F110,"netopen x p",p,0);
3931             debug(F110,"netopen x q",q,0);
3932
3933             /* Look for the port/service or a file/directory path */
3934             while (*p != '\0' && *p != ':' && *p != '/')
3935               p++;
3936             if (*p == ':') {
3937                 debug(F110,"netopen found port",q,0);
3938                 *p++ = '\0';            /* Found a port name or number */
3939                 r = p;
3940
3941                 /* Look for the end of port/service or a file/directory path */
3942                 while (*p != '\0' && *p != '/')
3943                     p++;
3944                 if (*p == '/')
3945                     *p++ = '\0';
3946
3947                 debug(F110,"netopen port",r,0);
3948                 ckstrncpy(tempservice,r,80);
3949                 ckstrncpy(temphost,q,256);
3950                 ckstrncpy(temppath,p,256);
3951                 ckstrncpy(namecopy,temphost,NAMECPYL);
3952                 debug(F110,"netopen tempservice",tempservice,0);
3953                 debug(F110,"netopen temphost",temphost,0);
3954                 debug(F110,"netopen temppath",temppath,0);
3955
3956                 /* move port/service to a buffer that won't go away */
3957                 x = strlen(namecopy);
3958                 p = namecopy + x + 1;
3959                 ckstrncpy(p, tempservice, NAMECPYL - x);
3960             } else {
3961                 /* Handle a path if we found one */
3962                 if (*p == '/')
3963                     *p++ = '\0';
3964                 ckstrncpy(temppath,p,256);
3965
3966                 /* We didn't find another port, but if q is a service */
3967                 /* then assume that namecopy is actually a host.      */
3968                 if (getservbyname(q,"tcp")) {
3969                     p = q;
3970                 } else {
3971 #ifdef RLOGCODE
3972                     /* rlogin is not a valid service */
3973                     if (!ckstrcmp("rlogin",namecopy,6,0)) {
3974                         ckstrncpy(namecopy,"login",NAMECPYL);
3975                     }
3976 #endif /* RLOGCODE */
3977                     /* iksd is not a valid service */
3978                     if (!ckstrcmp("iksd",namecopy,6,0)) {
3979                         ckstrncpy(namecopy,"kermit",NAMECPYL);
3980                     }
3981                     /* Reconstruct namecopy */
3982                     ckstrncpy(tempservice,namecopy,80);
3983                     ckstrncpy(temphost,q,256);
3984                     ckstrncpy(namecopy,temphost,NAMECPYL);
3985                     debug(F110,"netopen tempservice",tempservice,0);
3986                     debug(F110,"netopen temphost",temphost,0);
3987                     debug(F110,"netopen temppath",temppath,0);
3988
3989                     /* move port/service to a buffer that won't go away */
3990                     x = strlen(namecopy);
3991                     p = namecopy + x + 1;
3992                     ckstrncpy(p, tempservice, NAMECPYL - x - 1);
3993                 }
3994             }
3995             debug(F110,"netopen URL result: host",namecopy,0);
3996             debug(F110,"netopen URL result: service",p,0);
3997             debug(F110,"netopen URL result: path",temppath,0);
3998
3999 #ifdef IKS_GET
4000             /* If we have set a path specified, we need to try to GET it */
4001             /* But we have another problem, we have to login first.  How */
4002             /* do we specify that a login must be done before the GET?   */
4003             /* The user's name if specified is in 'userid' and the       */
4004             /* password if any is in 'pwbuf'.                            */
4005             if ( temppath[0] ) {
4006                 extern int action;
4007                 extern char * cmarg;
4008
4009                 if ( !uidfound ) {
4010                     /* If no userid was specified as part of the URL but
4011                      * a path was specified, then we
4012                      * set the user name to anonymous and the password
4013                      * to the current userid.
4014                      */
4015                     ckstrncpy(pwbuf,uidbuf,PWBUFL);
4016                     ckstrncat(pwbuf,"@",PWBUFL);
4017                     pwflg = 1;
4018                     pwcrypt = 0;
4019                     ckstrncpy(uidbuf,"anonymous",UIDBUFLEN);
4020                 }
4021
4022                 /*
4023                  * If a file path was specified we perform the GET
4024                  * operation and then terminate the connection.
4025                  *
4026                  * If a directory was given instead of a file, then
4027                  * we should REMOTE CD to the directory and list its
4028                  * contents.  But how do we tell the difference?
4029                  */
4030                 makestr(&cmarg,temppath);
4031                 action = 'r';
4032             }
4033 #endif /* IKS_GET */
4034         }
4035 #endif /* CK_URL */
4036     } else {                            /* Otherwise use telnet */
4037         p = "telnet";
4038     }
4039 /*
4040   By the time we get here, namecopy[] should hold the null-terminated
4041   hostname or address, and p should point to the service name or number.
4042 */
4043     debug(F110,"netopen host",namecopy,0);
4044     debug(F110,"netopen service requested",p,0);
4045
4046    /* Use the service port to set the default protocol type if necessary */
4047     if (ttnproto == NP_DEFAULT)
4048        setnproto(p);
4049
4050     ckstrncpy(namecopy2,namecopy,NAMECPYL);
4051     service = ckgetservice(namecopy,p,namecopy,NAMECPYL);
4052     if (!service) {
4053         fprintf(stderr, "Can't find port for service %s\n", p);
4054 #ifdef TGVORWIN
4055         debug(F101,"netopen can't get service","",socket_errno);
4056 #else
4057         debug(F101,"netopen can't get service","",errno);
4058 #endif /* TGVORWIN */
4059         errno = 0;                  /* (rather than mislead) */
4060         return(-1);
4061     } else {
4062         if (!ckstrcmp(namecopy,namecopy2,-1,0))
4063           namecopy2[0] = '\0';
4064         ckstrncpy(svcbuf,ckuitoa(ntohs(service->s_port)),sizeof(svcbuf));
4065         debug(F110,"netopen service ok",svcbuf,0);
4066     }
4067
4068 #ifdef RLOGCODE
4069     if (service && !strcmp("login",p) && service->s_port != htons(513)) {
4070         fprintf(stderr,
4071                 "  Warning: login service on port %d instead of port 513\n",
4072                  ntohs(service->s_port)
4073                 );
4074         fprintf(stderr, "  Edit SERVICES file if RLOGIN fails to connect.\n");
4075         debug(F101,"tcpsrv_open login on port","",ntohs(service->s_port));
4076     }
4077 #endif /* RLOGCODE */
4078
4079 #ifndef NOHTTP
4080    /* For HTTP connections we must preserve the original hostname and */
4081    /* service requested so we can include them in the Host header.    */
4082     ckmakmsg(http_host_port,sizeof(http_host_port),namecopy,":",
4083               ckitoa(ntohs(service->s_port)),NULL);
4084
4085     /* 'namecopy' contains the name of the host to which we want to connect */
4086     /* 'svcbuf'   contains the service name                                 */
4087     /* 'service->s_port' contains the port number in network byte order     */
4088
4089     /* If we are using an http proxy, we need to create a buffer containing */
4090     /*   hostname:port-number                                               */
4091     /* to pass to the http_connect() function.  Then we need to replace     */
4092     /* 'namecopy' with the name of the proxy server and the service->s_port */
4093     /* with the port number of the proxy (default port 80).                 */
4094
4095     if ( tcp_http_proxy ) {
4096         ckmakmsg(proxycopy,sizeof(proxycopy),namecopy,":",
4097                  ckuitoa(ntohs(service->s_port)),NULL);
4098         ckstrncpy(namecopy,tcp_http_proxy,NAMECPYL);
4099
4100         p = namecopy;                       /* Was a service requested? */
4101         while (*p != '\0' && *p != ':') p++; /* Look for colon */
4102         if (*p == ':') {                    /* Have a colon */
4103             debug(F110,"netopen name has colon",namecopy,0);
4104             *p++ = '\0';                    /* Get service name or number */
4105         } else {
4106             strcpy(++p,"http");
4107         }
4108
4109         service = ckgetservice(namecopy,p,namecopy,NAMECPYL);
4110         if (!service) {
4111             fprintf(stderr, "Can't find port for service %s\n", p);
4112 #ifdef TGVORWIN
4113             debug(F101,"netopen can't get service for proxy","",socket_errno);
4114 #else
4115             debug(F101,"netopen can't get service for proxy","",errno);
4116 #endif /* TGVORWIN */
4117             errno = 0;                  /* (rather than mislead) */
4118             return(-1);
4119         }
4120         ckstrncpy(p,ckuitoa(ntohs(service->s_port)),NAMECPYL-(p-namecopy));
4121
4122     }
4123 #endif /* NOHTTP */
4124
4125     /* Set up socket structure and get host address */
4126
4127     bzero((char *)&r_addr, sizeof(r_addr));
4128     debug(F100,"netopen bzero ok","",0);
4129 /*
4130    NOTE: Originally the inet_addr() check was #ifdef NT, but is enabled for
4131    all as of 20 Sep 97, to allow people to "set host" to a specific numeric IP
4132    address without going through the multihomed host sequence and winding up
4133    at a different place than the one requested.
4134 */
4135 #ifdef INADDR_NONE
4136     debug(F101,"netopen INADDR_NONE defined","",INADDR_NONE);
4137 #else /* INADDR_NONE */
4138     debug(F100,"netopen INADDR_NONE not defined","",0);
4139 #endif /* INADDR_NONE */
4140 #ifdef INADDRX
4141     debug(F100,"netopen INADDRX defined","",0);
4142 #else /* INADDRX */
4143     debug(F100,"netopen INADDRX not defined","",0);
4144 #endif /* INADDRX */
4145
4146 #ifndef NOMHHOST
4147 #ifdef INADDRX
4148     iax = inet_addr(namecopy);
4149     debug(F111,"netopen inet_addr",namecopy,iax.s_addr);
4150 #else /* INADDRX */
4151 #ifdef INADDR_NONE
4152     iax.s_addr = inet_addr(namecopy);
4153     debug(F111,"netopen inet_addr",namecopy,iax.s_addr);
4154 #else /* INADDR_NONE */
4155 #ifdef SOLARIS
4156     /* In Solaris inet_addr() is of type in_addr_t which is uint32_t */
4157     /* (unsigned) yet it returns -1 (signed) on failure. */
4158     /* It makes a difference in 64-bit builds. */
4159     rc_inet_addr = inet_addr(namecopy); /* Assign return code to an int */
4160     iax = (unsigned) rc_inet_addr;      /* and from there to whatever.. */
4161 #else
4162 #ifndef datageneral
4163     iax = (unsigned int) inet_addr(namecopy);
4164 #else
4165     iax = -1L;
4166 #endif /* datageneral */
4167 #endif /* SOLARIS */
4168     debug(F111,"netopen rc_inet_addr",namecopy,rc_inet_addr);
4169     debug(F111,"netopen inet_addr",namecopy,iax);
4170 #endif /* INADDR_NONE */
4171 #endif /* INADDRX */
4172
4173     dns = 0;
4174     if (
4175 /* This might give warnings on 64-bit platforms but they should be harmless */
4176 /* because INADDR_NONE should be all 1's anyway, thus the OR part is */
4177 /* probably superfluous -- not sure why it's even there, maybe it should be */
4178 /* removed. */
4179 #ifdef SOLARIS
4180         rc_inet_addr == -1
4181 #else
4182 #ifdef INADDR_NONE
4183         iax.s_addr == INADDR_NONE /* || iax.s_addr == (unsigned long) -1L */
4184 #else /* INADDR_NONE */
4185         iax < 0
4186 #endif /* INADDR_NONE */
4187 #endif /* SOLARIS */
4188         ) {
4189         if (!quiet) {
4190             printf(" DNS Lookup... ");
4191             fflush(stdout);
4192         }
4193         if ((host = gethostbyname(namecopy)) != NULL) {
4194             debug(F110,"netopen gethostbyname != NULL",namecopy,0);
4195             host = ck_copyhostent(host);
4196             dns = 1;                    /* Remember we performed dns lookup */
4197             r_addr.sin_family = host->h_addrtype;
4198             if (tcp_rdns && host->h_name && host->h_name[0]
4199 #ifndef NOHTTP
4200                  && (tcp_http_proxy == NULL)
4201 #endif /* NOHTTP */
4202                 ) {
4203 #ifdef COMMENT
4204                 ckstrncpy(xxname,host->h_name,XXNAMELEN);
4205                 debug(F110,"netopen xxname[1]",xxname,0);
4206                 if ((XXNAMELEN - (int)strlen(name)) > ((int)strlen(svcbuf)+1)){
4207                     ckstrncat(xxname,":",XXNAMELEN - (int)strlen(xxname));
4208                     ckstrncat(xxname,svcbuf,XXNAMELEN - (int)strlen(xxname));
4209                     debug(F110,"netopen xxname[2]",xxname,0);
4210                 }
4211                 name = (char *)xxname;
4212 #else
4213                 ckstrncpy(name,host->h_name,80);  /* Bad Bad Bad */
4214                 if ( (80-strlen(name)) > (strlen(svcbuf)+1) ) {
4215                     ckstrncat(name,":",80-strlen(name));
4216                     ckstrncat(name,svcbuf,80-strlen(name));
4217                 }
4218 #endif  /* COMMENT */
4219             }
4220             debug(F110,"netopen name after lookup",name,0);
4221
4222 #ifdef HADDRLIST
4223 #ifdef h_addr
4224             /* This is for trying multiple IP addresses - see <netdb.h> */
4225             if (!(host->h_addr_list))
4226               return(-1);
4227             bcopy(host->h_addr_list[0],
4228                   (caddr_t)&r_addr.sin_addr,
4229                   host->h_length
4230                   );
4231 #else
4232             bcopy(host->h_addr, (caddr_t)&r_addr.sin_addr, host->h_length);
4233 #endif /* h_addr */
4234 #else  /* HADDRLIST */
4235 #ifdef HPUX6
4236             r_addr.sin_addr.s_addr = (u_long)host->h_addr;
4237 #else  /* HPUX6 */
4238             bcopy(host->h_addr, (caddr_t)&r_addr.sin_addr, host->h_length);
4239 #endif  /* HPUX6 */
4240 #endif /* HADDRLIST */
4241
4242 #ifndef HPUX6
4243             debug(F111,"BCOPY","host->h_length",host->h_length);
4244 #endif  /* HPUX6 */
4245         }
4246     }
4247 #endif /* NOMHHOST */
4248
4249     debug(F101,"netopen dns","",dns);
4250
4251     if (!dns) {
4252 #ifdef INADDRX
4253 /* inet_addr() is of type struct in_addr */
4254         struct in_addr ina;
4255         unsigned long uu;
4256         debug(F100,"netopen gethostbyname == NULL: INADDRX","",0);
4257         ina = inet_addr(namecopy);
4258         uu = *(unsigned int *)&ina;
4259 #else /* Not INADDRX */
4260 /* inet_addr() is unsigned long */
4261         unsigned long uu;
4262         debug(F100,"netopen gethostbyname == NULL: Not INADDRX","",0);
4263         uu = inet_addr(namecopy);
4264 #endif /* INADDRX */
4265         debug(F101,"netopen uu","",uu);
4266         if (
4267 #ifdef INADDR_NONE
4268             !(uu == INADDR_NONE || uu == (unsigned int) -1L)
4269 #else   /* INADDR_NONE */
4270             uu != ((unsigned long)-1)
4271 #endif /* INADDR_NONE */
4272             ) {
4273             r_addr.sin_addr.s_addr = uu;
4274             r_addr.sin_family = AF_INET;
4275         } else {
4276 #ifdef VMS
4277             fprintf(stdout, "\r\n");    /* complete any previous message */
4278 #endif /* VMS */
4279             fprintf(stderr, "Can't get address for %s\n", namecopy);
4280 #ifdef TGVORWIN
4281             debug(F101,"netopen can't get address","",socket_errno);
4282 #else
4283             debug(F101,"netopen can't get address","",errno);
4284 #endif /* TGVORWIN */
4285             errno = 0;                  /* Rather than mislead */
4286             return(-1);
4287         }
4288     }
4289
4290     /* Get a file descriptor for the connection. */
4291
4292     r_addr.sin_port = service->s_port;
4293     ckstrncpy(ipaddr,(char *)inet_ntoa(r_addr.sin_addr),20);
4294     debug(F110,"netopen trying",ipaddr,0);
4295     if (!quiet && *ipaddr) {
4296         printf(" Trying %s... ", ipaddr);
4297         fflush(stdout);
4298     }
4299
4300     /* Loop to try additional IP addresses, if any. */
4301
4302     do {
4303 #ifdef EXCELAN
4304         send_socket.sin_family = AF_INET;
4305         send_socket.sin_addr.s_addr = 0;
4306         send_socket.sin_port = 0;
4307         if ((ttyfd = socket(SOCK_STREAM, (struct sockproto *)0,
4308                             &send_socket, SO_REUSEADDR)) < 0)
4309 #else  /* EXCELAN */
4310 #ifdef NT
4311 #ifdef COMMENT_X
4312        /*
4313          Must make sure that all sockets are opened in
4314          Non-overlapped mode since we use the standard
4315          C RTL functions to read and write data.
4316          But it doesn't seem to work as planned.
4317        */
4318           {
4319               int optionValue = SO_SYNCHRONOUS_NONALERT;
4320               if (setsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE,
4321                              (char *) &optionValue, sizeof(optionValue))
4322                   != NO_ERROR)
4323                 return(-1);
4324           }
4325 #endif /* COMMENT */
4326 #endif /* NT */
4327
4328         if ((ttyfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
4329 #endif /* EXCELAN */
4330             {
4331 #ifdef EXCELAN
4332                 experror("TCP socket error");
4333 #else
4334 #ifdef VMS
4335                 fprintf(stdout, "\r\n"); /* complete any previous stdout */
4336 #endif /* VMS */
4337 #ifdef TGVORWIN
4338 #ifdef OLD_TWG
4339                 errno = socket_errno;
4340 #endif /* OLD_TWG */
4341                 socket_perror("TCP socket error");
4342                 debug(F101,"netopen socket error","",socket_errno);
4343 #else
4344                 perror("TCP socket error");
4345                 debug(F101,"netopen socket error","",errno);
4346 #endif /* TGVORWIN */
4347 #endif /* EXCELAN */
4348                 return (-1);
4349             }
4350         errno = 0;
4351
4352 #ifdef RLOGCODE
4353        /* Not part of the RLOGIN RFC, but the BSD implementation     */
4354        /* requires that the client port be a priviliged port (<1024) */
4355        /* on a Unix system this would require SuperUser permissions  */
4356        /* thereby saying that the root of the Unix system has given  */
4357        /* permission for this connection to be created               */
4358        if (service->s_port == htons((unsigned short)RLOGIN_PORT)) {
4359            static unsigned short lport = 1024;  /* max reserved port */
4360 #ifdef OS2
4361            int s_errno;
4362 #endif /* OS2 */
4363
4364            lport--;                     /* Make sure we do not reuse a port */
4365            if (lport == 512)
4366              lport = 1023;
4367
4368            sin.sin_family = AF_INET;
4369            if (tcp_address) {
4370 #ifdef INADDRX
4371                inaddrx = inet_addr(tcp_address);
4372                sin.sin_addr.s_addr = *(unsigned long *)&inaddrx;
4373 #else
4374                sin.sin_addr.s_addr = inet_addr(tcp_address);
4375 #endif /* INADDRX */
4376            } else
4377              sin.sin_addr.s_addr = INADDR_ANY;
4378            while (1) {
4379                sin.sin_port = htons(lport);
4380                if (bind(ttyfd, (struct sockaddr *)&sin, sizeof(sin)) >= 0)
4381                  break;
4382 #ifdef OS2
4383                s_errno = socket_errno;
4384                if (s_errno && /* OS2 bind fails with 0, if already in use */
4385 #ifdef NT
4386                    s_errno != WSAEADDRINUSE
4387 #else
4388                    s_errno != SOCEADDRINUSE &&
4389                    s_errno != (SOCEADDRINUSE - SOCBASEERR)
4390 #endif /* NT */
4391                    )
4392 #else /* OS2 */
4393 #ifdef TGVORWIN
4394                  if (socket_errno != EADDRINUSE)
4395 #else
4396                  if (errno != EADDRINUSE)
4397 #endif /* TGVORWIN */
4398 #endif /* OS2 */
4399                    {
4400 #ifdef COMMENT
4401                        printf("\nBind failed with errno %d  for port %d.\n",
4402 #ifdef OS2
4403                               s_errno
4404 #else
4405 #ifdef TGVORWIN
4406                               socket_errno
4407 #else
4408                               errno
4409 #endif /* TGVORWIN */
4410 #endif /* OS2 */
4411                               , lport
4412                               );
4413 #ifdef OS2
4414                        debug(F101,"rlogin bind failed","",s_errno);
4415 #else
4416 #ifdef TGVORWIN
4417                        debug(F101,"rlogin bind failed","",socket_errno);
4418 #ifdef OLD_TWG
4419                        errno = socket_errno;
4420 #endif /* OLD_TWG */
4421                        socket_perror("rlogin bind");
4422 #else
4423                        debug(F101,"rlogin bind failed","",errno);
4424                        perror("rlogin bind");
4425 #endif /* TGVORWIN */
4426 #endif /* OS2 */
4427 #else  /* COMMENT */
4428 #ifdef OS2
4429                        debug(F101,"rlogin bind s_errno","",s_errno);
4430                        perror("rlogin bind");
4431 #else
4432 #ifdef VMS
4433                        printf("\r\n");  /* complete any previous message */
4434 #endif /* VMS */
4435 #ifdef TGVORWIN
4436                        debug(F101,"rlogin bind socket_errno","",socket_errno);
4437 #ifdef OLD_TWG
4438                        errno = socket_errno;
4439 #endif /* OLD_TWG */
4440                        socket_perror("rlogin bind");
4441 #else
4442                        debug(F101,"rlogin bind errno","",errno);
4443                        perror("rlogin bind");
4444 #endif /* TGVORWIN */
4445 #endif /* OS2 */
4446                        debug(F101,"rlogin local port","",lport);
4447 #endif /* COMMENT */
4448                        netclos();
4449                        return -1;
4450                    }
4451                lport--;
4452                if (lport == 512 /* lowest reserved port to use */ ) {
4453                    printf("\nNo reserved ports available.\n");
4454                    netclos();
4455                    return -1;
4456                }
4457            }
4458            debug(F101,"rlogin lport","",lport);
4459            ttnproto = NP_RLOGIN;
4460        } else
4461 #endif /* RLOGCODE  */
4462
4463        /* If a specific TCP address on the local host is desired we */
4464        /* must bind it to the socket.                               */
4465 #ifndef datageneral
4466          if (tcp_address) {
4467              int s_errno;
4468
4469              debug(F110,"netopen binding socket to",tcp_address,0);
4470              bzero((char *)&sin,sizeof(sin));
4471              sin.sin_family = AF_INET;
4472 #ifdef INADDRX
4473              inaddrx = inet_addr(tcp_address);
4474              sin.sin_addr.s_addr = *(unsigned long *)&inaddrx;
4475 #else
4476              sin.sin_addr.s_addr = inet_addr(tcp_address);
4477 #endif /* INADDRX */
4478              sin.sin_port = 0;
4479              if (bind(ttyfd, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
4480                  s_errno = socket_errno; /* Save error code */
4481 #ifdef TCPIPLIB
4482                  socket_close(ttyfd);
4483 #else /* TCPIPLIB */
4484                  close(ttyfd);
4485 #endif /* TCPIPLIB */
4486                  ttyfd = -1;
4487                  wasclosed = 1;
4488                  errno = s_errno;       /* and report this error */
4489                  debug(F101,"netopen bind errno","",errno);
4490                  return(-1);
4491              }
4492          }
4493 #endif /* datageneral */
4494
4495 /* Now connect to the socket on the other end. */
4496
4497 #ifdef EXCELAN
4498         if (connect(ttyfd, &r_addr) < 0)
4499 #else
4500 #ifdef NT
4501           WSASafeToCancel = 1;
4502 #endif /* NT */
4503         if (connect(ttyfd, (struct sockaddr *)&r_addr, sizeof(r_addr)) < 0)
4504 #endif /* EXCELAN */
4505           {
4506 #ifdef NT
4507               WSASafeToCancel = 0;
4508 #endif /* NT */
4509 #ifdef OS2
4510               i = socket_errno;
4511 #else /* OS2 */
4512 #ifdef TGVORWIN
4513               i = socket_errno;
4514 #else
4515               i = errno;                /* Save error code */
4516 #endif /* TGVORWIN */
4517 #endif /* OS2 */
4518 #ifdef RLOGCODE
4519               if (
4520 #ifdef OS2
4521                  i && /* OS2 bind fails with 0, if already in use */
4522 #ifdef NT
4523                  i == WSAEADDRINUSE
4524 #else
4525                  (i == SOCEADDRINUSE ||
4526                  i == (SOCEADDRINUSE - SOCBASEERR))
4527 #endif /* NT */
4528 #else /* OS2 */
4529 #ifdef TGVORWIN
4530                   socket_errno == EADDRINUSE
4531 #else
4532                   errno == EADDRINUSE
4533 #endif /* TGVORWIN */
4534 #endif /* OS2 */
4535                   && ttnproto == NP_RLOGIN) {
4536 #ifdef TCPIPLIB
4537                    socket_close(ttyfd); /* Close it. */
4538 #else
4539                    close(ttyfd);
4540 #endif /* TCPIPLIB */
4541                    continue;            /* Try a different lport */
4542                }
4543 #endif /* RLOGCODE */
4544 #ifdef HADDRLIST
4545 #ifdef h_addr
4546               if (host && host->h_addr_list && host->h_addr_list[1]) {
4547                   perror("");
4548                   host->h_addr_list++;
4549                   bcopy(host->h_addr_list[0],
4550                         (caddr_t)&r_addr.sin_addr,
4551                         host->h_length);
4552
4553                   ckstrncpy(ipaddr,(char *)inet_ntoa(r_addr.sin_addr),20);
4554                   debug(F110,"netopen h_addr_list",ipaddr,0);
4555                   if (!quiet && *ipaddr) {
4556                       printf(" Trying %s... ", ipaddr);
4557                       fflush(stdout);
4558                   }
4559 #ifdef TCPIPLIB
4560                   socket_close(ttyfd); /* Close it. */
4561 #else
4562                   close(ttyfd);
4563 #endif /* TCPIPLIB */
4564                   continue;
4565               }
4566 #endif /* h_addr */
4567 #endif  /* HADDRLIST */
4568               netclos();
4569               ttyfd = -1;
4570               wasclosed = 1;
4571               ttnproto = NP_NONE;
4572               errno = i;                /* And report this error */
4573 #ifdef EXCELAN
4574               if (errno) experror("netopen connect");
4575 #else
4576 #ifdef TGVORWIN
4577               debug(F101,"netopen connect error","",socket_errno);
4578               /* if (errno) socket_perror("netopen connect"); */
4579 #ifdef OLD_TWG
4580               errno = socket_errno;
4581 #endif /* OLD_TWG */
4582               if (!quiet)
4583                 socket_perror("netopen connect");
4584 #else /* TGVORWIN */
4585               debug(F101,"netopen connect errno","",errno);
4586 #ifdef VMS
4587               if (!quiet)
4588                 perror("\r\nFailed");
4589 #else
4590               if (!quiet)
4591                 perror("Failed");
4592 #endif /* VMS */
4593 #ifdef DEC_TCPIP
4594               if (!quiet)
4595                 perror("netopen connect");
4596 #endif /* DEC_TCPIP */
4597 #ifdef CMU_TCPIP
4598               if (!quiet)
4599                 perror("netopen connect");
4600 #endif /* CMU_TCPIP */
4601 #endif /* TGVORWIN */
4602 #endif /* EXCELAN */
4603               return(-1);
4604           }
4605 #ifdef NT
4606         WSASafeToCancel = 0;
4607 #endif /* NT */
4608         isconnect = 1;
4609     } while (!isconnect);
4610
4611 #ifdef NON_BLOCK_IO
4612     on = 1;
4613     x = socket_ioctl(ttyfd,FIONBIO,&on);
4614     debug(F101,"netopen FIONBIO","",x);
4615 #endif /* NON_BLOCK_IO */
4616
4617 #ifdef NT_TCP_OVERLAPPED
4618     OverlappedWriteInit();
4619     OverlappedReadInit();
4620 #endif /* NT_TCP_OVERLAPPED */
4621
4622     ttnet = nett;                       /* TCP/IP (sockets) network */
4623
4624 #ifndef NOHTTP
4625     /* We have succeeded in connecting to the HTTP PROXY.  So now we   */
4626     /* need to attempt to connect through the proxy to the actual host */
4627     /* If that is successful, we have to pretend that we made a direct */
4628     /* connection to the actual host.                                  */
4629
4630     if ( tcp_http_proxy ) {
4631 #ifdef OS2
4632         char * agent = "Kermit 95";             /* Default user agent */
4633 #else
4634         char * agent = "C-Kermit";
4635 #endif /* OS2 */
4636
4637         if (http_connect(ttyfd,
4638                          tcp_http_proxy_agent ? tcp_http_proxy_agent : agent,
4639                          NULL,
4640                          tcp_http_proxy_user,
4641                          tcp_http_proxy_pwd,
4642                          0,
4643                          proxycopy
4644                          ) < 0) {
4645             netclos();
4646             return(-1);
4647         }
4648
4649         ckstrncpy(namecopy,proxycopy,NAMECPYL);
4650         p = namecopy;                       /* Was a service requested? */
4651         while (*p != '\0' && *p != ':') p++; /* Look for colon */
4652         *p = '\0';
4653     }
4654 #endif /* NOHTTP */
4655
4656     /* Jeff - Does this next block of code that set's the protocol */
4657     /* need to be here anymore?  5/10/2000                         */
4658
4659     /* There are certain magic port numbers that when used require */
4660     /* the use of specific protocols.  Check this now before we    */
4661     /* set the SO_OOBINLINE state or we might get it wrong.        */
4662     x = ntohs((unsigned short)service->s_port);
4663     svcnum = x;
4664     /* See if the service is TELNET. */
4665     if (x == TELNET_PORT) {
4666         /* Yes, so if raw port not requested */
4667 #ifdef COMMENT
4668         /* Jeff 2005/12/30 */
4669         if (ttnproto != NP_TCPRAW && ttnproto != NP_SSL_RAW && 
4670             ttnproto != NP_TLS_RAW && ttnproto != NP_NONE)
4671 #else
4672         /* fdc 2005/12/04 */
4673         if (ttnproto != NP_TCPRAW && ttnproto != NP_NONE)
4674 #endif  /* COMMENT */
4675           ttnproto = NP_TELNET;         /* Select TELNET protocol. */
4676     }
4677 #ifdef RLOGCODE
4678     else if (x == RLOGIN_PORT) {
4679         ttnproto = NP_RLOGIN;
4680     }
4681 #ifdef CK_KERBEROS
4682     /* There is no good way to do this.  If the user didn't tell    */
4683     /* which one to use up front.  We may guess wrong if the user   */
4684     /* has both Kerberos versions installed and valid TGTs for each */
4685     else if (x == KLOGIN_PORT &&
4686              ttnproto != NP_K4LOGIN &&
4687              ttnproto != NP_K5LOGIN) {
4688         if (ck_krb5_is_installed() &&
4689             ck_krb5_is_tgt_valid())
4690           ttnproto = NP_K5LOGIN;
4691         else if (ck_krb4_is_installed() && ck_krb4_is_tgt_valid())
4692           ttnproto = NP_K4LOGIN;
4693         else
4694           ttnproto = NP_K4LOGIN;
4695     } else if (x == EKLOGIN_PORT &&
4696                ttnproto != NP_EK4LOGIN &&
4697                ttnproto != NP_EK5LOGIN) {
4698         if (ck_krb5_is_installed() && ck_krb5_is_tgt_valid())
4699           ttnproto = NP_EK5LOGIN;
4700         else if (ck_krb4_is_installed() && ck_krb4_is_tgt_valid())
4701           ttnproto = NP_EK4LOGIN;
4702         else
4703           ttnproto = NP_EK4LOGIN;
4704     }
4705 #endif /* CK_KERBEROS */
4706 #endif /* RLOGCODE */
4707 #ifdef IKS_OPTION
4708     else if (x == KERMIT_PORT) {        /* IKS uses Telnet protocol */
4709         if (ttnproto == NP_NONE)
4710           ttnproto = NP_KERMIT;
4711     }
4712 #endif /* IKS_OPTION */
4713
4714 #ifdef SO_OOBINLINE
4715 /*
4716   The symbol SO_OOBINLINE is not known to Ultrix 2.0.
4717   It means "leave out of band data inline".  The normal value is 0x0100,
4718   but don't try this on systems where the symbol is undefined.
4719 */
4720 /*
4721   Note from Jeff Altman: 12/13/95
4722   In implementing rlogin protocol I have come to the conclusion that it is
4723   a really bad idea to read out-of-band data inline.
4724   At least Windows and OS/2 does not handle this well.
4725   And if you need to know that data is out-of-band, then it becomes
4726   absolutely pointless.
4727
4728   Therefore, at least on OS2 and Windows (NT) I have changed the value of
4729   on to 0, so that out-of-band data stays out-of-band.
4730
4731   12/18/95
4732   Actually, OOB data should be read inline when possible.  Especially with
4733   protocols that don't care about the Urgent flag.  This is true with Telnet.
4734   With Rlogin, you need to be able to catch OOB data.  However, the best
4735   way to do this is to set a signal handler on SIGURG.  This isn't possible
4736   on OS/2 and Windows.  But it is in UNIX.  We will also need OOB data for
4737   FTP so better create a general mechanism.
4738
4739   The reason for making OOB data be inline is that the standard ttinc/ttoc
4740   calls can be used for reading that data on UNIX systems.  If we didn't
4741   have the OOBINLINE option set then we would have to use recv(,MSG_OOB)
4742   to read it.
4743 */
4744 #ifdef RLOGCODE
4745 #ifdef TCPIPLIB
4746     if (ttnproto == NP_RLOGIN
4747 #ifdef CK_KERBEROS
4748         || ttnproto == NP_K4LOGIN || ttnproto == NP_EK4LOGIN
4749         || ttnproto == NP_K5LOGIN || ttnproto == NP_EK5LOGIN
4750 #endif /* CK_KERBEROS */
4751       )
4752       on = 0;
4753 #else /* TCPIPLIB */
4754     if (ttnproto == NP_RLOGIN
4755 #ifdef CK_KERBEROS
4756          || ttnproto == NP_K4LOGIN || ttnproto == NP_EK4LOGIN
4757          || ttnproto == NP_K5LOGIN || ttnproto == NP_EK5LOGIN
4758 #endif /* CK_KERBEROS */
4759          ) {
4760         debug(F100,"Installing rlogoobh on SIGURG","",0);
4761         signal(SIGURG, rlogoobh);
4762         on = 0;
4763     } else {
4764         debug(F100,"Ignoring SIGURG","",0);
4765         signal(SIGURG, SIG_DFL);
4766     }
4767 #endif /* TCPIPLIB */
4768 #endif /* RLOGCODE */
4769
4770 #ifdef datageneral
4771     setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
4772 #else
4773 #ifdef BSD43
4774     setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
4775 #else
4776 #ifdef OSF1
4777     setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
4778 #else
4779 #ifdef POSIX
4780     setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
4781 #else
4782 #ifdef MOTSV88R4
4783     setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
4784 #else
4785 #ifdef SOLARIS
4786 /*
4787   Maybe this applies to all SVR4 versions, but the other (else) way has been
4788   compiling and working fine on all the others, so best not to change it.
4789 */
4790     setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
4791 #else
4792 #ifdef OSK
4793     setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
4794 #else
4795 #ifdef OS2
4796     {
4797         int rc;
4798         rc = setsockopt(ttyfd,
4799                         SOL_SOCKET,
4800                         SO_OOBINLINE,
4801                         (char *) &on,
4802                         sizeof on
4803                         );
4804         debug(F111,"setsockopt SO_OOBINLINE",on ? "on" : "off" ,rc);
4805     }
4806 #else
4807 #ifdef VMS /* or, at least, VMS with gcc */
4808     setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
4809 #else
4810 #ifdef CLIX
4811     setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
4812 #else
4813     setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE, &on, sizeof on);
4814 #endif /* CLIX */
4815 #endif /* VMS */
4816 #endif /* OS2 */
4817 #endif /* OSK */
4818 #endif /* SOLARIS */
4819 #endif /* MOTSV88R4 */
4820 #endif /* POSIX */
4821 #endif /* BSD43 */
4822 #endif /* OSF1 */
4823 #endif /* datageneral */
4824 #endif /* SO_OOBINLINE */
4825
4826 #ifndef NOTCPOPTS
4827 #ifndef datageneral
4828 #ifdef SOL_SOCKET
4829 #ifdef TCP_NODELAY
4830     no_delay(ttyfd,tcp_nodelay);
4831 #endif /* TCP_NODELAY */
4832 #ifdef SO_KEEPALIVE
4833     keepalive(ttyfd,tcp_keepalive);
4834 #endif /* SO_KEEPALIVE */
4835 #ifdef SO_LINGER
4836     ck_linger(ttyfd,tcp_linger, tcp_linger_tmo);
4837 #endif /* SO_LINGER */
4838 #ifdef SO_SNDBUF
4839     sendbuf(ttyfd,tcp_sendbuf);
4840 #endif /* SO_SNDBUF */
4841 #ifdef SO_RCVBUF
4842     recvbuf(ttyfd,tcp_recvbuf);
4843 #endif /* SO_RCVBUF */
4844 #endif /* SOL_SOCKET */
4845 #endif /* datageneral */
4846 #endif /* NOTCPOPTS */
4847
4848 #ifndef datageneral
4849     /* Find out our own IP address. */
4850     /* We need the l_addr structure for [E]KLOGIN. */
4851     l_slen = sizeof(l_addr);
4852     bzero((char *)&l_addr, l_slen);
4853 #ifndef EXCELAN
4854     if (!getsockname(ttyfd, (struct sockaddr *)&l_addr, &l_slen)) {
4855         char * s = (char *)inet_ntoa(l_addr.sin_addr);
4856         ckstrncpy(myipaddr, s, 20);
4857         debug(F110,"getsockname",myipaddr,0);
4858     }
4859 #endif /* EXCELAN */
4860 #endif /* datageneral */
4861
4862 /*
4863   This is really only needed for Kerberos IV but is useful information in any
4864   case.  If we connect to a name that is really a pool, we need to get the
4865   name of the machine we are actually connecting to for K4 to authenticate
4866   properly.  This way we also update the names properly.
4867
4868   However, it is a security hole when used with insecure DNS.
4869
4870   Note: This does not work on Windows 95 or Windows NT 3.5x.  This is because
4871   of the Microsoft implementation of gethostbyaddr() in both Winsock 1.1
4872   and Winsock 2.0 on those platforms.  Their algorithm is:
4873
4874   1. Check the HOSTENT cache.
4875   2. Check the HOSTS file at %SystemRoot%\System32\DRIVERS\ETC.
4876   3. Do a DNS query if the DNS server is configured for name resolution.
4877   4. Do an additional NetBIOS remote adapter status to an IP address for its
4878      NetBIOS name table. This step is specific only to the Windows NT version
4879      3.51 implementation.
4880
4881   The problem is the use of the HOSTENT cache.  It means that gethostbyaddr()
4882   can not be used to resolve the real name of machine if it was originally
4883   accessed by an alias used to represent a cluster.
4884 */
4885      if ((tcp_rdns && dns || tcp_rdns == SET_ON
4886 #ifdef CK_KERBEROS
4887          || tcp_rdns == SET_AUTO &&
4888           (ck_krb5_is_installed() || ck_krb4_is_installed())
4889 #endif /* CK_KERBEROS */
4890          )
4891 #ifndef NOHTTP
4892           && (tcp_http_proxy == NULL)
4893 #endif /* NOHTTP */
4894 #ifdef CK_SSL
4895           && !(ssl_only_flag || tls_only_flag)
4896 #endif /* CK_SSL */
4897          ) {
4898 #ifdef NT
4899         if (isWin95())
4900           sleep(1);
4901 #endif /* NT */
4902         if (!quiet) {
4903             printf(" Reverse DNS Lookup... ");
4904             fflush(stdout);
4905         }
4906         if (host = gethostbyaddr((char *)&r_addr.sin_addr,4,PF_INET)) {
4907             char * s;
4908             host = ck_copyhostent(host);
4909             debug(F100,"netopen gethostbyname != NULL","",0);
4910             if (!quiet) {
4911                 printf("(OK)\n");
4912                 fflush(stdout);
4913             }
4914             s = host->h_name;
4915             if (!s) {                   /* This can happen... */
4916                 debug(F100,"netopen host->h_name is NULL","",0);
4917                 s = "";
4918             }
4919             /* Something is wrong with inet_ntoa() on HPUX 10.xx */
4920             /* The compiler says "Integral value implicitly converted to */
4921             /* pointer in assignment."  The prototype is right there */
4922             /* in <arpa/inet.h> so what's the problem? */
4923             /* Ditto in HP-UX 5.x, but not 8.x or 9.x... */
4924             if (!*s) {                  /* No name so substitute the address */
4925                 debug(F100,"netopen host->h_name is empty","",0);
4926                 s = inet_ntoa(r_addr.sin_addr); /* Convert address to string */
4927                 if (!s)                 /* Trust No 1 */
4928                   s = "";
4929                 if (*s) {               /* If it worked, use this string */
4930                     ckstrncpy(ipaddr,s,20);
4931                 }
4932                 s = ipaddr;             /* Otherwise stick with the IP */
4933                 if (!*s)                /* or failing that */
4934                   s = namecopy;         /* the name we were called with. */
4935             }
4936             if (*s) {                   /* Copying into our argument? */
4937                 ckstrncpy(name,s,80);   /* Bad Bad Bad */
4938                 if ( (80-strlen(name)) > (strlen(svcbuf)+1) ) {
4939                     ckstrncat(name,":",80-strlen(name));
4940                     ckstrncat(name,svcbuf,80-strlen(name));
4941                 }
4942             }
4943             if (!quiet && *s
4944 #ifndef NOICP
4945                 && !doconx
4946 #endif /* NOICP */
4947                 ) {
4948                 printf(" %s connected on port %s\n",s,p);
4949 #ifdef BETADEBUG
4950                 /* This is simply for testing the DNS entries */
4951                 if (host->h_aliases) {
4952                     char ** a = host->h_aliases;
4953                     while (*a) {
4954                         printf(" alias => %s\n",*a);
4955                         a++;
4956                     }
4957                 }
4958 #endif /* BETADEBUG */
4959             }
4960         } else {
4961             if (!quiet) printf("Failed.\n");
4962         }
4963     } else if (!quiet) printf("(OK)\n");
4964     if (!quiet) fflush(stdout);
4965
4966     /* This should already have been done but just in case */
4967     ckstrncpy(ipaddr,(char *)inet_ntoa(r_addr.sin_addr),20);
4968
4969 #ifdef CK_SECURITY
4970
4971     /* Before Initialization Telnet/Rlogin Negotiations Init Kerberos */
4972 #ifndef NOHTTP
4973     if (tcp_http_proxy) {
4974         for (i=strlen(proxycopy); i >= 0 ; i--)
4975             if ( proxycopy[i] == ':' )
4976                 proxycopy[i] = '\0';
4977     }
4978 #endif /* NOHTTP */
4979     ck_auth_init(
4980 #ifndef NOHTTP
4981                  tcp_http_proxy ? proxycopy :
4982 #endif /* NOHTTP */
4983                  (tcp_rdns && host && host->h_name && host->h_name[0]) ?
4984                  (char *)host->h_name : (namecopy2[0] ? namecopy2 : 
4985                                         (namecopy[0] ? namecopy : ipaddr)),
4986                  ipaddr,
4987                  uidbuf,
4988                  ttyfd
4989                  );
4990 #endif /* CK_SECURITY */
4991 #ifdef CK_SSL
4992     if (ck_ssleay_is_installed()) {
4993         if (!ssl_tn_init(SSL_CLIENT)) {
4994             debug(F100,"netopen ssl_tn_init() failed","",0);
4995             if (bio_err!=NULL) {
4996                 BIO_printf(bio_err,"ssl_tn_init() failed\n");
4997                 ERR_print_errors(bio_err);
4998             } else {
4999                 fflush(stderr);
5000                 fprintf(stderr,"ssl_tn_init() failed\n");
5001                 ERR_print_errors_fp(stderr);
5002             }
5003             if (tls_only_flag || ssl_only_flag) {
5004                 debug(F100,"netopen ssl/tls required","",0);
5005                 netclos();
5006                 return(-1);
5007             }
5008
5009             /* we will continue to accept the connection   */
5010             /* without SSL or TLS support unless required. */
5011             if ( TELOPT_DEF_S_ME_MODE(TELOPT_START_TLS) != TN_NG_MU )
5012                 TELOPT_DEF_S_ME_MODE(TELOPT_START_TLS) = TN_NG_RF;
5013             if ( TELOPT_DEF_S_U_MODE(TELOPT_START_TLS) != TN_NG_MU )
5014                 TELOPT_DEF_S_U_MODE(TELOPT_START_TLS) = TN_NG_RF;
5015             if ( TELOPT_DEF_C_ME_MODE(TELOPT_START_TLS) != TN_NG_MU )
5016                 TELOPT_DEF_C_ME_MODE(TELOPT_START_TLS) = TN_NG_RF;
5017             if ( TELOPT_DEF_C_U_MODE(TELOPT_START_TLS) != TN_NG_MU )
5018                 TELOPT_DEF_C_U_MODE(TELOPT_START_TLS) = TN_NG_RF;
5019         } else if ( ck_ssl_outgoing(ttyfd) < 0 ) {
5020             debug(F100,"ck_ssl_outgoing() failed","",0);
5021             netclos();
5022             return(-1);
5023         }
5024     }
5025 #endif /* CK_SSL */
5026
5027 #ifdef RLOGCODE
5028     if (ttnproto == NP_RLOGIN
5029 #ifdef CK_KERBEROS
5030         || ttnproto == NP_K4LOGIN || ttnproto == NP_EK4LOGIN
5031         || ttnproto == NP_K5LOGIN || ttnproto == NP_EK5LOGIN
5032 #endif /* CK_KERBEROS */
5033         ) {                             /* Similar deal for rlogin */
5034         if (rlog_ini(((tcp_rdns && host && host->h_name && host->h_name[0]) ?
5035                       (CHAR *)host->h_name : (CHAR *)ipaddr),
5036                      service->s_port,
5037                      &l_addr,&r_addr
5038                      ) < 0) {
5039             debug(F100,"rlogin initialization failed","",0);
5040             netclos();
5041             return(-1);
5042         }
5043     } else
5044 #endif /* RLOGCODE */
5045     if (tn_ini() < 0) {                 /* Start Telnet negotiations. */
5046         netclos();
5047         return(-1);                     /* Gone, so open failed.  */
5048     }
5049     if (ttchk() < 0) {
5050         netclos();
5051         return(-1);
5052     }
5053 #ifdef CK_KERBEROS
5054 #ifdef KRB5_U2U
5055    if ( ttnproto == NP_K5U2U ) {
5056        if (k5_user_to_user_client_auth()) {
5057            netclos();
5058            return(-1);
5059        }
5060    }
5061 #endif /* KRB5_U2U */
5062 #endif /* CK_KERBEROS */
5063
5064     debug(F101,"netopen service","",svcnum);
5065     debug(F110,"netopen name",name,0);
5066     debug(F110,"netopen ipaddr",ipaddr,0);
5067     ckstrncpy(hostipaddr,ipaddr,63);
5068
5069     if (lcl) if (*lcl < 0)              /* Local mode. */
5070       *lcl = 1;
5071 #endif /* TCPSOCKET */
5072     return(0);                          /* Done. */
5073 }
5074
5075 /*  N E T C L O S  --  Close current network connection.  */
5076
5077 #ifndef NOLOCAL
5078 _PROTOTYP(VOID slrestor,(VOID));
5079 #ifdef CK_SSL
5080 int tls_norestore = 0;
5081 #endif /* CK_SSL */
5082 #endif /* NOLOCAL */
5083
5084 int
5085 netclos() {
5086     static int close_in_progress = 0;
5087     int x = 0, y, z;
5088     debug(F101,"netclos","",ttyfd);
5089
5090 #ifdef NETLEBUF
5091     if (!tt_push_inited)
5092       le_init();
5093 #endif /* NETLEBUF */
5094
5095     if (ttyfd == -1)                    /* Was open? */
5096       return(0);                        /* Wasn't. */
5097
5098     if (close_in_progress)
5099       return(0);
5100     close_in_progress = 1;              /* Remember */
5101
5102 #ifndef NOLOCAL
5103     /* This function call should not be here since this is a direct call */
5104     /* from an I/O routine to a user interface level function.  However, */
5105     /* the reality is that we do not have pure interfaces.  If we ever   */
5106     /* decide to clean this up the UI level should assign this function  */
5107     /* via a pointer assignment.  - Jeff 9/10/1999                       */
5108 #ifdef CK_SSL
5109     if (!tls_norestore)
5110 #endif /* CK_SSL */
5111       slrestor();
5112 #endif /* NOLOCAL */
5113 #ifdef OS2
5114     RequestTCPIPMutex(SEM_INDEFINITE_WAIT);
5115 #else /* OS2 */
5116     if (ttyfd > -1)                     /* Was. */
5117 #endif /* OS2 */
5118       {
5119 #ifdef VMS
5120           y = 1;                          /* Turn on nonblocking reads */
5121           z = socket_ioctl(ttyfd,FIONBIO,&y);
5122           debug(F111,"netclos FIONBIO","on",z);
5123 #endif /* VMS */
5124 #ifdef TNCODE
5125           if (ttnproto == NP_TELNET) {
5126             if (!TELOPT_ME(TELOPT_LOGOUT)
5127 #ifdef COMMENT
5128 /* Jeff 2005/12/30 */
5129 #ifdef CK_SSL
5130                  && !ssl_raw_flag && !tls_raw_flag
5131 #endif  /* CK_SSL */
5132 #endif  /* COMMENT */
5133                 ) {
5134                 /* Send LOGOUT option before close */
5135                 if (tn_sopt(DO,TELOPT_LOGOUT) >= 0) {
5136                     TELOPT_UNANSWERED_DO(TELOPT_LOGOUT) = 1;
5137                     /* It would be nice to call tn_wait but we can't */
5138                 }
5139             }
5140             tn_push();                  /* Place any waiting data into input*/
5141           }
5142 #endif /* TNCODE */
5143 #ifdef CK_SSL
5144           if (ssl_active_flag) {
5145               if (ssl_debug_flag)
5146                 BIO_printf(bio_err,"calling SSL_shutdown\n");
5147               SSL_shutdown(ssl_con);
5148               ssl_active_flag = 0;
5149           }
5150           if (tls_active_flag) {
5151               if (ssl_debug_flag)
5152                 BIO_printf(bio_err,"calling SSL_shutdown\n");
5153               SSL_shutdown(tls_con);
5154               tls_active_flag = 0;
5155           }
5156 #endif /* CK_SSL */
5157 #ifdef VMS
5158           ck_cancio();                  /* Cancel any outstanding reads. */
5159 #endif /* VMS */
5160 #ifdef TCPIPLIB
5161           x = socket_close(ttyfd);      /* Close it. */
5162 #else
5163 #ifndef OS2
5164 #ifdef IBMX25
5165         if (ttnet == NET_IX25) {
5166             /* riehm: should send a disc_req - but only if link is still OK */
5167             x = x25clear();
5168             close(ttyfd);
5169             if (x25serverfd) {
5170                   /* we were the passive client of a server, now we
5171                    * go back to being the normal client.
5172                    * I hope that kermit can cope with the logic that
5173                    * there can still be a connection after netclos
5174                    * has been called.
5175                    */
5176                   ttyfd = x25serverfd;
5177                   x25serverfd = 0;
5178                   /*
5179                    * need to close the server connection too - because
5180                    * all file descriptors connected to the NPI have the
5181                    * same status.
5182                    *
5183                    * The problem is that any waiting connections get
5184                    * lost, the client doesn't realise, and hangs.
5185                    */
5186                   netclos();
5187               }
5188             x25_state = X25_CLOSED;     /* riehm: dead code? */
5189         } else
5190 #endif /* IBMX25 */
5191           x = close(ttyfd);
5192 #endif /* OS2 */
5193 #endif /* TCPIPLIB */
5194       }
5195     ttyfd = -1;                         /* Mark it as closed. */
5196     wasclosed = 1;
5197 #ifdef OS2
5198     ReleaseTCPIPMutex();
5199 #endif /* OS2 */
5200 #ifdef TNCODE
5201 #ifdef CK_FORWARD_X
5202     fwdx_close_all();                   /* Shut down any Forward X sockets */
5203 #endif /* CK_FORWARD_X */
5204     tn_reset();                   /* The Reset Telnet Option table.  */
5205     debug(F100,"netclose setting tn_init = 0","",0);
5206     tn_init = 0;                        /* Remember about telnet protocol... */
5207     sstelnet = 0;                       /* Client-side Telnet */
5208 #endif /* TNCODE */
5209     *ipaddr = '\0';                     /* Zero the IP address string */
5210     tcp_incoming = 0;                   /* No longer incoming */
5211     /* Don't reset ttnproto so that we can remember which protocol is in use */
5212
5213 #ifdef TCPIPLIB
5214 /*
5215   Empty the internal buffers so they won't be used as invalid input on
5216   the next connect attempt (rlogin).
5217 */
5218     ttibp = 0;
5219     ttibn = 0;
5220 #endif /* TCPIPLIB */
5221 #ifdef CK_KERBEROS
5222     /* If we are automatically destroying Kerberos credentials on Close */
5223     /* do it now. */
5224 #ifdef KRB4
5225     if (krb4_autodel == KRB_DEL_CL) {
5226         extern struct krb_op_data krb_op;
5227         krb_op.version = 4;
5228         krb_op.cache = NULL;
5229         ck_krb4_destroy(&krb_op);
5230     }
5231 #endif /* KRB4 */
5232 #ifdef KRB5
5233     if (krb5_autodel == KRB_DEL_CL) {
5234         extern struct krb_op_data krb_op;
5235         extern char * krb5_d_cc;
5236         krb_op.version = 5;
5237         krb_op.cache = krb5_d_cc;
5238         ck_krb5_destroy(&krb_op);
5239     }
5240 #endif /* KRB5 */
5241 #endif /* CK_KERBEROS */
5242     close_in_progress = 0;              /* Remember we are done. */
5243     return(x);
5244 }
5245
5246 #ifdef OS2
5247 int
5248 os2socketerror( int s_errno ) {
5249 #ifdef OS2ONLY
5250     if (s_errno > 0 && s_errno <= SOCBASEERR) {
5251         /* in OS/2, there is a problem with threading in that
5252          * the value of errno is not thread safe.  It can be
5253          * set to a value from a previous library call and if
5254          * it was not cleared it will appear here.  Only treat
5255          * valid socket error codes as errors in this function.
5256          */
5257         debug(F100,"os2socketerror errno.h","",0);
5258         socket_errno = 0;
5259         return(0);
5260     }
5261 #endif /* OS2ONLY */
5262
5263     switch (s_errno) {
5264       case 0:                           /* NO ERROR */
5265         debug(F100,"os2socketerror NOERROR","",0);
5266         return(0);
5267 #ifdef NT
5268       case WSAECONNRESET:
5269 #else /* NT */
5270       case SOCECONNRESET:
5271       case SOCECONNRESET - SOCBASEERR:
5272 #endif /* NT */
5273         debug(F100,"os2socketerror ECONRESET","",0);
5274         tn_debug("ECONRESET");
5275         netclos();              /* *** *** */
5276         return(-1);             /* Connection is broken. */
5277 #ifdef NT
5278       case WSAECONNABORTED:
5279 #else /* NT */
5280       case SOCECONNABORTED:
5281       case SOCECONNABORTED - SOCBASEERR:
5282 #endif /* NT */
5283         debug(F100,"os2socketerror ECONNABORTED","",0);
5284         tn_debug("ECONNABORTED");
5285         netclos();              /* *** *** */
5286         return(-1);             /* Connection is broken. */
5287 #ifdef NT
5288       case WSAENETRESET:
5289 #else /* NT */
5290       case SOCENETRESET:
5291       case SOCENETRESET - SOCBASEERR:
5292 #endif /* NT */
5293         debug(F100,"os2socketerror ENETRESET","",0);
5294         tn_debug("ENETRESET");
5295         netclos();              /* *** *** */
5296         return(-1);             /* Connection is broken. */
5297 #ifdef NT
5298       case WSAENOTCONN:
5299 #else /* NT */
5300       case SOCENOTCONN:
5301       case SOCENOTCONN - SOCBASEERR:
5302 #endif /* NT */
5303         debug(F100,"os2socketerror ENOTCONN","",0);
5304         tn_debug("ENOTCONN");
5305         netclos();                      /* *** *** */
5306         return(-1);                     /* Connection is broken. */
5307 #ifdef NT
5308       case WSAESHUTDOWN:
5309         debug(F100,"os2socketerror ESHUTDOWN","",0);
5310         tn_debug("ESHUTDOWN");
5311         netclos();                      /* *** *** */
5312         return(-1);                     /* Connection is broken. */
5313 #endif /* NT */
5314 #ifdef NT
5315       case WSAEWOULDBLOCK:
5316 #else
5317       case SOCEWOULDBLOCK:
5318       case SOCEWOULDBLOCK - SOCBASEERR:
5319 #endif /* NT */
5320         debug(F100,"os2socketerror EWOULDBLOCK","",0);
5321         return(0);
5322 #ifdef NT
5323       case ERROR_IO_INCOMPLETE:
5324       case ERROR_IO_PENDING:
5325       case ERROR_OPERATION_ABORTED:
5326         return(0);
5327 #endif /* NT */
5328       default:
5329         return(-2);
5330     }
5331     return(0);
5332 }
5333 #endif /* OS2 */
5334
5335 /*  N E T T C H K  --  Check if network up, and how many bytes can be read */
5336 /*
5337   Returns number of bytes waiting, or -1 if connection has been dropped.
5338 */
5339 int                                     /* Check how many bytes are ready */
5340 nettchk() {                             /* for reading from network */
5341 #ifdef TCPIPLIB
5342     long count = 0;
5343     int x = 0, z;
5344     long y;
5345     char c;
5346     int rc;
5347 #ifdef NT
5348     extern int ionoblock;               /* For Overlapped I/O */
5349 #endif /* NT */
5350
5351     debug(F101,"nettchk entry ttibn","",ttibn);
5352     debug(F101,"nettchk entry ttibp","",ttibp);
5353
5354 #ifdef NETLEBUF
5355     {
5356         int n = 0;
5357         if (ttpush >= 0)
5358           n++;
5359         n += le_inbuf();
5360         if (n > 0)
5361           return(n);
5362     }
5363 #endif /* NETLEBUF */
5364
5365 #ifndef OS2
5366 #ifndef BEBOX
5367     socket_errno = 0; /* This is a function call in NT, and BeOS */
5368 #endif /* BEBOX */
5369 #endif /* OS2 */
5370
5371     if (ttyfd == -1) {
5372         debug(F100,"nettchk socket is closed","",0);
5373         return(-1);
5374     }
5375 /*
5376   Note: this socket_ioctl() call does NOT return an error if the
5377   connection has been broken.  (At least not in MultiNet.)
5378 */
5379 #ifdef COMMENT
5380 /*  Another trick that can be tried here is something like this: */
5381
5382     if (ttnet == NET_TCPB) {
5383         char dummy;
5384         x = read(ttyfd,&dummy,0);       /* Try to read nothing */
5385         if (x < 0) {                    /* "Connection reset by peer" */
5386             perror("TCP/IP");           /* or somesuch... */
5387             ttclos(0);                  /* Close our end too. */
5388             return(-1);
5389         }
5390     }
5391 #endif /* COMMENT */
5392
5393
5394 #ifdef CK_SSL
5395     if (ssl_active_flag) {
5396 #ifndef IKSDONLY
5397 #ifdef OS2
5398         if ( IsConnectMode() ) {
5399             debug(F101,"nettchk (ssl_active_flag) returns","",count);
5400             return(0);
5401         }
5402 #endif /* OS2 */
5403 #endif /* IKSDONLY */
5404         count = SSL_pending(ssl_con);
5405         if (count < 0) {
5406             debug(F111,"nettchk","SSL_pending error",count);
5407             netclos();
5408             return(-1);
5409         }
5410         if ( count > 0 )
5411             return(count);                  /* Don't perform a read */
5412     } else if (tls_active_flag) {
5413 #ifndef IKSDONLY
5414 #ifdef OS2
5415         if ( IsConnectMode() ) {
5416             debug(F101,"nettchk (tls_active_flag) returns","",count);
5417             return(0);
5418         }
5419 #endif /* OS2 */
5420 #endif /* IKSDONLY */
5421         count = SSL_pending(tls_con);
5422         if (count < 0) {
5423             debug(F111,"nettchk","TLS_pending error",count);
5424             netclos();
5425             return(-1);
5426         }
5427         if ( count > 0 )
5428             return(count);                  /* Don't perform a read */
5429     } else
5430 #endif /* CK_SSL */
5431
5432     if (socket_ioctl(ttyfd,FIONREAD,
5433 #ifdef COMMENT
5434     /* Now we've changed the ioctl(..,..,x) prototype for DECC to (void *) */
5435 #ifdef __DECC
5436     /* NOTE: "&count" might need to be "(char *)&count" in some settings. */
5437                      /* Cast needed for DECC 4.1 & later? */
5438                      /* Maybe, but __DECC_VER only exists in 5.0 and later */
5439                      (char *)
5440 #endif /* __DECC */
5441 #endif /* COMMENT */
5442                      &count
5443                      ) < 0) {
5444         debug(F101,"nettchk socket_ioctl error","",socket_errno);
5445         /* If the connection is gone, the connection is gone. */
5446         netclos();
5447 #ifdef NT_TCP_OVERLAPPED
5448         /* Is there anything in the overlapped I/O buffers? */
5449         count += OverlappedDataWaiting();
5450 #endif /* NT_TCP_OVERLAPPED */
5451         count += ttibn;
5452         return(count>0?count:-1);
5453     }
5454     debug(F101,"nettchk count","",count);
5455 #ifdef NT_TCP_OVERLAPPED
5456     /* Is there anything in the overlapped I/O buffers? */
5457     count += OverlappedDataWaiting();
5458     debug(F101,"nettchk count w/overlapped","",count);
5459 #endif /* NT_TCP_OVERLAPPED */
5460
5461 #ifdef OS2
5462 #ifndef IKSDONLY
5463     if ( IsConnectMode() ) {
5464         debug(F101,"nettchk (FIONREAD) returns","",count);
5465         return(count);
5466     }
5467 #endif /* IKSDONLY */
5468 #endif /* OS2 */
5469
5470 /* For the sake of efficiency, if there is still data in the ttibuf */
5471 /* do not go to the bother of checking to see of the connection is  */
5472 /* still valid.  The handle is still good, so just return the count */
5473 /* of the bytes that we already have left to process.               */
5474 #ifdef OS2
5475     if ( count > 0 || ttibn > 0 ) {
5476         count+=ttibn;
5477         debug(F101,"nettchk (count+ttibn > 0) returns","",count);
5478         return(count);
5479     } else {
5480         RequestTCPIPMutex(SEM_INDEFINITE_WAIT);
5481         if ( ttibn == 0 )
5482             ttibp = 0;      /* reset for next read */
5483     }
5484 #else /* OS2 */
5485     if ( count > 0 || ttibn > 0 ) {
5486         debug(F101,"nettchk returns","",count+ttibn);
5487         return(count+ttibn);
5488     }
5489     ttibn = ttibp = 0;
5490 #endif /* OS2 */
5491
5492 /*
5493   The following code works well in most settings, but messes things up in
5494   others, including CMU/Tek TCP/IP and UCX 2.0, where it somehow manages to
5495   make it impossible to ever make a new connection to the same host again with
5496   CONNECT, once it has been logged out from the first time.  Not even if you
5497   HANGUP first, or SET HOST<CR>, or SET LINE<CR>.  Reportedly, however, it
5498   does work OK in later releases of UCX.  But there is no way we can
5499   accommodate both old and new -- we might have static linking or dynamic
5500   linking, etc etc.  If we have static, I only have access to 2.0, where this
5501   doesn't work, etc etc blah blah.
5502
5503   In the following lines, we define a symbol NOCOUNT for builds where we want
5504   to omit this code.  By default, it is omitted for CMU/Tek.  You can force
5505   omission of it for other combinations by defining NOCOUNT in CFLAGS.  You
5506   can force inclusion of this code, even for CMU/Tek, by including NONOCOUNT
5507   in CFLAGS.
5508 */
5509 #ifdef NONOCOUNT
5510 #ifdef NOCOUNT
5511 #undef NOCOUNT
5512 #endif /* NOCOUNT */
5513 #else
5514 #ifndef NOCOUNT
5515 #ifdef CMU_TCPIP
5516 #define NOCOUNT
5517 #endif /* CMU_TCPIP */
5518 #endif /* NOCOUNT */
5519 #endif /* NONOCOUNT */
5520
5521
5522     /* From this point forward we have a possible race condition in K95
5523      * due to its use of multiple threads.  Therefore, we must ensure
5524      * that only one thread attempt to read/write from the socket at a
5525      * time.  Otherwise, it is possible for a buffer to be overwritten.
5526      */
5527     /* we know now that count >= 0 and that ttibn == 0 */
5528
5529     if (count == 0
5530 #ifdef RLOGCODE
5531 #ifdef CK_KERBEROS
5532         && ttnproto != NP_EK4LOGIN && ttnproto != NP_EK5LOGIN
5533 #endif /* CK_KERBEROS */
5534 #endif /* RLOGCODE */
5535         ) {
5536         int s_errno = 0;
5537 #ifndef NOCOUNT
5538 /*
5539   Here we need to tell the difference between a 0 count on an active
5540   connection, and a 0 count because the remote end of the socket broke the
5541   connection.  There is no mechanism in TGV MultiNet (or WIN/TCP?) to query
5542   the status of the connection, so we have to do a read.  -1 means there was
5543   no data available (socket_errno == EWOULDBLOCK), 0 means the connection is
5544   down.  But if, by chance, we actually get a character, we have to put it
5545   where it won't be lost.
5546 */
5547 #ifndef NON_BLOCK_IO
5548 #ifdef OS2
5549 #ifdef CK_SSL
5550         RequestSSLMutex(SEM_INDEFINITE_WAIT);
5551 #endif /* CK_SSL */
5552 #endif /* OS2 */
5553         y = 1;                          /* Turn on nonblocking reads */
5554         z = socket_ioctl(ttyfd,FIONBIO,&y);
5555         debug(F111,"nettchk FIONBIO","on",z);
5556 #ifdef OS2
5557 #ifdef CK_SSL
5558         ReleaseSSLMutex();
5559 #endif /* CK_SSL */
5560 #endif /* OS2 */
5561 #endif /* NON_BLOCK_IO */
5562 #ifdef NT_TCP_OVERLAPPED
5563         ionoblock = 1;                  /* For Overlapped I/O */
5564 #endif /* NT_TCP_OVERLAPPED */
5565 #ifdef CK_SSL
5566         if ( ssl_active_flag || tls_active_flag ) {
5567 #ifdef OS2
5568           ssl_read:
5569             x = SSL_read( ssl_active_flag?ssl_con:tls_con,
5570                           &ttibuf[ttibp+ttibn],
5571                           TTIBUFL-ttibp-ttibn );
5572             switch (SSL_get_error(ssl_active_flag?ssl_con:tls_con,x)) {
5573             case SSL_ERROR_NONE:
5574                 debug(F111,"nettchk SSL_ERROR_NONE","x",x);
5575                 break;
5576             case SSL_ERROR_WANT_WRITE:
5577                 debug(F100,"nettchk SSL_ERROR_WANT_WRITE","",0);
5578                 x = -1;
5579                 break;
5580             case SSL_ERROR_WANT_READ:
5581                 debug(F100,"nettchk SSL_ERROR_WANT_READ","",0);
5582                 x = -1;
5583                 break;
5584             case SSL_ERROR_SYSCALL:
5585                 if ( x == 0 ) { /* EOF */
5586                     netclos();
5587                     rc = -1;
5588                     goto nettchk_return;
5589               } else {
5590 #ifdef NT
5591                   int gle = GetLastError();
5592 #endif /* NT */
5593 #ifndef NON_BLOCK_IO
5594 #ifdef OS2
5595 #ifdef CK_SSL
5596                   RequestSSLMutex(SEM_INDEFINITE_WAIT);
5597 #endif /* CK_SSL */
5598 #endif /* OS2 */
5599                   y = 0;                          /* Turn off nonblocking reads */
5600                   z = socket_ioctl(ttyfd,FIONBIO,&y);
5601                   debug(F111,"nettchk FIONBIO","off",z);
5602 #ifdef OS2
5603 #ifdef CK_SSL
5604                   ReleaseSSLMutex();
5605 #endif /* CK_SSL */
5606 #endif /* OS2 */
5607 #endif /* NON_BLOCK_IO */
5608 #ifdef NT_TCP_OVERLAPPED
5609                   ionoblock = 0;                  /* For Overlapped I/O */
5610 #endif /* NT_TCP_OVERLAPPED */
5611 #ifdef NT
5612                   debug(F111,"nettchk SSL_ERROR_SYSCALL",
5613                          "GetLastError()",gle);
5614                   rc = os2socketerror(gle);
5615                   if (rc == -1)
5616                       rc = -2;
5617                   else if ( rc == -2 )
5618                       rc = -1;
5619                   goto nettchk_return;
5620 #endif /* NT */
5621                   break;
5622               }
5623           case SSL_ERROR_WANT_X509_LOOKUP:
5624                 debug(F100,"nettchk SSL_ERROR_WANT_X509_LOOKUP","",0);
5625                 break;
5626             case SSL_ERROR_SSL:
5627                 if (bio_err!=NULL) {
5628                     int len;
5629                     extern char ssl_err[];
5630                     BIO_printf(bio_err,"nettchk() SSL_ERROR_SSL\n");
5631                     ERR_print_errors(bio_err);
5632                     len = BIO_read(bio_err,ssl_err,SSL_ERR_BFSZ);
5633                     ssl_err[len < SSL_ERR_BFSZ ? len : SSL_ERR_BFSZ] = '\0';
5634                     debug(F110,"nettchk SSL_ERROR_SSL",ssl_err,0);
5635                     if (ssl_debug_flag)
5636                         printf(ssl_err);
5637                 } else if (ssl_debug_flag) {
5638                     debug(F100,"nettchk SSL_ERROR_SSL","",0);
5639                     fflush(stderr);
5640                     fprintf(stderr,"nettchk() SSL_ERROR_SSL\n");
5641                     ERR_print_errors_fp(stderr);
5642                 }
5643 #ifdef COMMENT
5644                 netclos();
5645                 rc = -1;
5646                 goto nettchk_return;
5647 #else
5648                 x = -1;
5649                 break;
5650 #endif
5651           case SSL_ERROR_ZERO_RETURN:
5652                 debug(F100,"nettchk SSL_ERROR_ZERO_RETURN","",0);
5653                 netclos();
5654                 rc = -1;
5655                 goto nettchk_return;
5656             default:
5657                 debug(F100,"nettchk SSL_ERROR_?????","",0);
5658                 netclos();
5659                 rc = -1;
5660                 goto nettchk_return;
5661             }
5662 #else /* OS2 */
5663             /* Do not block */
5664             x = -1;
5665 #endif /* OS2 */
5666         } else
5667 #endif /* CK_SSL */
5668         {
5669 #ifdef OS2
5670         x = socket_read(ttyfd,&ttibuf[ttibp+ttibn],
5671                          TTIBUFL-ttibp-ttibn);  /* Returns -1 if no data */
5672 #else /* OS2 */
5673         x = socket_read(ttyfd,&c,1);    /* Returns -1 if no data */
5674 #endif /* OS2 */
5675         }
5676         s_errno = socket_errno;         /* socket_errno may be a function */
5677         debug(F101,"nettchk socket_read","",x);
5678
5679 #ifndef NON_BLOCK_IO
5680 #ifdef OS2
5681 #ifdef CK_SSL
5682         RequestSSLMutex(SEM_INDEFINITE_WAIT);
5683 #endif /* CK_SSL */
5684 #endif /* OS2 */
5685         y = 0;                          /* Turn off nonblocking reads */
5686         z = socket_ioctl(ttyfd,FIONBIO,&y);
5687         debug(F111,"nettchk FIONBIO","off",z);
5688 #ifdef OS2
5689 #ifdef CK_SSL
5690         ReleaseSSLMutex();
5691 #endif /* CK_SSL */
5692 #endif /* OS2 */
5693 #endif /* NON_BLOCK_IO */
5694 #ifdef NT_TCP_OVERLAPPED
5695         ionoblock = 0;                  /* For Overlapped I/O */
5696 #endif /* NT_TCP_OVERLAPPED */
5697
5698         if (x == -1) {
5699             debug(F101,"nettchk socket_read errno","",s_errno);
5700 #ifdef OS2
5701             if (os2socketerror(s_errno) < 0) {
5702                 rc = -1;
5703                 goto nettchk_return;
5704             }
5705 #endif /* OS2 */
5706         } else if (x == 0) {
5707             debug(F100,"nettchk connection closed","",0);
5708             netclos();                  /* *** *** */
5709             rc = -1;
5710             goto nettchk_return;
5711         }
5712         if (x >= 1) {                   /* Oops, actually got a byte? */
5713 #ifdef OS2
5714             /* In OS/2 we read directly into ttibuf[] */
5715             ckhexdump("nettchk got real data",&ttibuf[ttibp+ttibn],x);
5716             ttibn += x;
5717 #else /* OS2 */
5718 #ifdef CK_SSL
5719             if ( ssl_active_flag || tls_active_flag ) {
5720                 ckhexdump("nettchk got real data",&ttibuf[ttibp+ttibn],x);
5721                 ttibn += x;
5722             } else 
5723 #endif /* CK_SSL */
5724             {
5725                 debug(F101,"nettchk socket_read char","",c);
5726                 debug(F101,"nettchk ttibp","",ttibp);
5727                 debug(F101,"nettchk ttibn","",ttibn);
5728 /*
5729   In the case of Overlapped I/O the character would have come from
5730   the beginning of the buffer, so put it back.
5731 */
5732                 if (ttibp > 0) {
5733                     ttibp--;
5734                     ttibuf[ttibp] = c;
5735                     ttibn++;
5736                 } else {
5737                     ttibuf[ttibp+ttibn] = c;
5738                     ttibn++;
5739                 }
5740             }
5741 #endif /* OS2 */
5742         }
5743 #else /* NOCOUNT */
5744         if (ttnet == NET_TCPB) {
5745             char dummy;
5746             x = read(ttyfd,&dummy,0);   /* Try to read nothing */
5747             if (x < 0) {                /* "Connection reset by peer" */
5748                 perror("TCP/IP");       /* or somesuch... */
5749                 ttclos(0);              /* Close our end too. */
5750                 rc = -1;
5751                 goto nettchk_return;
5752             }
5753         }
5754 #endif /* NOCOUNT */
5755     }
5756 #ifdef CK_KERBEROS
5757 #ifdef KRB4
5758 #ifdef RLOGCODE
5759     if (ttnproto == NP_EK4LOGIN)
5760       count += krb4_des_avail(ttyfd);
5761 #endif /* RLOGCODE */
5762 #endif /* KRB4 */
5763 #ifdef KRB5
5764 #ifdef RLOGCODE
5765     if (ttnproto == NP_EK5LOGIN)
5766       count += krb5_des_avail(ttyfd);
5767 #endif /* RLOGCODE */
5768 #ifdef KRB5_U2U
5769     if (ttnproto == NP_K5U2U)
5770       count += krb5_u2u_avail(ttyfd);
5771 #endif /* KRB5_U2U */
5772 #endif /* KRB5 */
5773 #endif /* CK_KERBEROS */
5774
5775     debug(F101,"nettchk returns","",count+ttibn);
5776     rc = count + ttibn;
5777
5778   nettchk_return:
5779 #ifdef OS2
5780     ReleaseTCPIPMutex();
5781 #endif /* OS2 */
5782     return(rc);
5783
5784 #else /* Not TCPIPLIB */
5785 /*
5786   UNIX just uses ttchk(), in which the ioctl() calls on the file descriptor
5787   seem to work OK.
5788 */
5789     return(ttchk());
5790 #endif /* TCPIPLIB */
5791 /*
5792   But what about X.25?
5793 */
5794 }
5795
5796 #ifndef OS2
5797 VOID
5798 nettout(i) int i; {                     /* Catch the alarm interrupts */
5799     debug(F100,"nettout caught timeout","",0);
5800     ttimoff();
5801     cklongjmp(njbuf, -1);
5802 }
5803 #endif /* !OS2 */
5804
5805 #ifdef TCPIPLIB
5806
5807 VOID
5808 #ifdef CK_ANSIC
5809 donetinc(void * threadinfo)
5810 #else /* CK_ANSIC */
5811 donetinc(threadinfo) VOID * threadinfo;
5812 #endif /* CK_ANSIC */
5813 /* donetinc */ {
5814 #ifdef NTSIG
5815     extern int TlsIndex;
5816     setint();
5817     if (threadinfo) {                   /* Thread local storage... */
5818         TlsSetValue(TlsIndex,threadinfo);
5819     }
5820 #endif /* NTSIG */
5821 #ifdef CK_LOGIN
5822 #ifdef NT
5823 #ifdef IKSD
5824     if (inserver)
5825       setntcreds();
5826 #endif /* IKSD */
5827 #endif /* NT */
5828 #endif /* CK_LOGIN */
5829     while (1) {
5830         if (ttbufr() < 0)               /* Keep trying to refill it. */
5831           break;                        /* Till we get an error. */
5832         if (ttibn > 0)                  /* Or we get a character. */
5833           break;
5834     }
5835 }
5836 #endif /* TCPIPLIB */
5837
5838 VOID
5839 #ifdef CK_ANSIC
5840 failnetinc(void * threadinfo)
5841 #else /* CK_ANSIC */
5842 failnetinc(threadinfo) VOID * threadinfo;
5843 #endif /* CK_ANSIC */
5844 /* failnetinc */ {
5845     ; /* Nothing to do on an error */
5846 }
5847
5848 /* N E T X I N -- Input block of characters from network */
5849
5850 int
5851 netxin(n,buf) int n; CHAR * buf; {
5852     int len, i, j;
5853 #ifdef TCPIPLIB
5854     int rc;
5855 #endif /* TCPIPLIB */
5856
5857     if (ttyfd == -1) {
5858         debug(F100,"netxin socket is closed","",0);
5859         return(-2);
5860     }
5861 #ifdef CK_KERBEROS
5862 #ifdef KRB4
5863 #ifdef RLOGCODE
5864     if (ttnproto == NP_EK4LOGIN) {
5865         if ((len = krb4_des_read(ttyfd,buf,n)) < 0)
5866           return(-1);
5867         else
5868           return(len);
5869     }
5870 #endif /* RLOGCODE */
5871 #endif /* KRB4 */
5872 #ifdef KRB5
5873 #ifdef RLOGCODE
5874     if (ttnproto == NP_EK5LOGIN) {
5875         if ((len = krb5_des_read(ttyfd,(char *)buf,n,0)) < 0)
5876           return(-1);
5877         else
5878           return(len);
5879     }
5880 #endif /* RLOGCODE */
5881 #ifdef KRB5_U2U
5882     if (ttnproto == NP_K5U2U) {
5883         if ((len = krb5_u2u_read(ttyfd,(char *)buf,n)) < 0)
5884           return(-1);
5885         else
5886           return(len);
5887     }
5888 #endif /* KRB5_U2U */
5889 #endif /* KRB5 */
5890 #endif /* CK_KERBEROS */
5891
5892 #ifdef TCPIPLIB
5893 #ifdef OS2
5894     RequestTCPIPMutex(SEM_INDEFINITE_WAIT);
5895 #endif /* OS2 */
5896     if (ttibn == 0)
5897       if ((rc = ttbufr()) <= 0) {
5898 #ifdef OS2
5899         ReleaseTCPIPMutex();
5900 #endif /* OS2 */
5901         return(rc);
5902       }
5903
5904     if (ttibn <= n) {
5905         len = ttibn;
5906         memcpy(buf,&ttibuf[ttibp],len);         /* safe */
5907         ttibp += len;
5908         ttibn = 0;
5909     } else {
5910         memcpy(buf,&ttibuf[ttibp],n);           /* safe */
5911         ttibp += n;
5912         ttibn -= n;
5913         len = n;
5914     }
5915 #ifdef OS2
5916     ReleaseTCPIPMutex();
5917 #endif /* OS2 */
5918 #else /* TCPIPLIB */
5919     for (i = 0; i < n; i++) {
5920         if ((j = netinc(0)) < 0) {
5921             if (j < -1)
5922               return(j);
5923             else
5924               break;
5925         }
5926         buf[i] = j;
5927     }
5928     len = i;
5929 #endif /* TCPIPLIB */
5930
5931 #ifdef COMMENT
5932 #ifdef CK_ENCRYPTION
5933     /* This would be great if it worked.  But what if the buffer we read  */
5934     /* contains a telnet negotiation that changes the state of the        */
5935     /* encryption.  If so, we would be either decrypting unencrypted text */
5936     /* or not decrypting encrypted text.  So we must move this call to    */
5937     /* all functions that call ttxin().  In OS2 that means os2_netxin()   */
5938     /* where the Telnet Negotiations are handled.                         */
5939     if (u_encrypt)
5940       ck_tn_decrypt(buf,len);
5941 #endif /* CK_ENCRYPTION */
5942 #endif /* COMMENT */
5943
5944     return(len);
5945 }
5946
5947 /*  N E T I N C --  Input character from network */
5948
5949 #ifdef NETLEBUF
5950 #define LEBUF
5951 #endif /* NETLEBUF */
5952 #ifdef TTLEBUF
5953 #define LEBUF
5954 #endif /* TTLEBUF */
5955 #ifndef LEBUF
5956 #ifdef OS2
5957 #define LEBUF
5958 #endif /* OS2 */
5959 #endif /* LEBUF */
5960
5961 int
5962 netinc(timo) int timo; {
5963 #ifdef TCPIPLIB
5964     int x; unsigned char c;             /* The locals. */
5965
5966 #ifdef NETLEBUF
5967     if (ttpush >= 0) {
5968         debug(F111,"netinc","ttpush",ttpush);
5969         c = ttpush;
5970         ttpush = -1;
5971         return(c);
5972     }
5973     if (le_data) {
5974         if (le_getchar((CHAR *)&c) > 0) {
5975             debug(F111,"netinc le_getchar","c",c);
5976             return(c);
5977         }
5978     }
5979 #endif /* NETLEBUF */
5980
5981     if (ttyfd == -1) {
5982         debug(F100,"netinc socket is closed","",0);
5983         return(-2);
5984     }
5985
5986 #ifdef CK_KERBEROS
5987 #ifdef KRB4
5988 #ifdef RLOGCODE
5989     if (ttnproto == NP_EK4LOGIN) {
5990         if ((x = krb4_des_read(ttyfd,&c,1)) == 0)
5991           return(-1);
5992         else if (x < 0)
5993           return(-2);
5994         else
5995           return(c);
5996     }
5997 #endif /* RLOGCODE */
5998 #endif /* KRB4 */
5999 #ifdef KRB5
6000 #ifdef RLOGCODE
6001     if (ttnproto == NP_EK5LOGIN) {
6002         if ((x = krb5_des_read(ttyfd,&c,1,0)) == 0)
6003           return(-1);
6004         else if (x < 0)
6005           return(-2);
6006         else
6007           return(c);
6008     }
6009 #endif /* RLOGCODE */
6010 #ifdef KRB5_U2U
6011     if (ttnproto == NP_K5U2U) {
6012         if ((x = krb5_u2u_read(ttyfd,&c,1)) == 0)
6013           return(-1);
6014         else if (x < 0)
6015           return(-2);
6016         else
6017           return(c);
6018     }
6019 #endif /* KRB5_U2U */
6020 #endif /* KRB5 */
6021 #endif /* CK_KERBEROS */
6022
6023 #ifdef OS2
6024     RequestTCPIPMutex(SEM_INDEFINITE_WAIT);
6025 #endif /* OS2 */
6026     if (ttibn > 0) {                    /* Something in internal buffer? */
6027 #ifdef COMMENT
6028         debug(F100,"netinc char in buf","",0); /* Yes. */
6029 #endif /* COMMENT */
6030         x = 0;                          /* Success. */
6031     } else {                            /* Else must read from network. */
6032         x = -1;                         /* Assume failure. */
6033 #ifdef DEBUG
6034         debug(F101,"netinc goes to net, timo","",timo);
6035 #endif /* DEBUG */
6036 #ifdef CK_SSL
6037         /*
6038          * In the case of OpenSSL, it is possible that there is still
6039          * data waiting in the SSL session buffers that has not yet
6040          * been read by Kermit.  If this is the case we must process
6041          * it without calling select() because select() will not return
6042          * with an indication that there is data to be read from the
6043          * socket.  If there is no data pending in the SSL session
6044          * buffers then fall through to the select() code and wait for
6045          * some data to arrive.
6046          */
6047         if (ssl_active_flag) {
6048             x = SSL_pending(ssl_con);
6049             if (x < 0) {
6050                 debug(F111,"netinc","SSL_pending error",x);
6051                 netclos();
6052 #ifdef OS2
6053                 ReleaseTCPIPMutex();
6054 #endif /* OS2 */
6055                 return(-1);
6056             } else if ( x > 0 ) {
6057                 if ( ttbufr() >= 0 ) {
6058                     x = netinc(timo);
6059 #ifdef OS2
6060                     ReleaseTCPIPMutex();
6061 #endif /* OS2 */
6062                     return(x);
6063                 }
6064             }
6065             x = -1;
6066         } else if (tls_active_flag) {
6067             x = SSL_pending(tls_con);
6068             if (x < 0) {
6069                 debug(F111,"netinc","TLS_pending error",x);
6070                 netclos();
6071 #ifdef OS2
6072                 ReleaseTCPIPMutex();
6073 #endif /* OS2 */
6074                 return(-1);
6075             } else if ( x > 0 ) {
6076                 if ( ttbufr() >= 0 ) {
6077                     x = netinc(timo);
6078 #ifdef OS2
6079                     ReleaseTCPIPMutex();
6080 #endif /* OS2 */
6081                     return(x);
6082                 }
6083             }
6084             x = -1;
6085         }
6086 #endif /* CK_SSL */
6087 #ifndef LEBUF
6088         if (timo == 0) {                /* Untimed case. */
6089             while (1) {                 /* Wait forever if necessary. */
6090                 if (ttbufr() < 0)       /* Refill buffer. */
6091                   break;                /* Error, fail. */
6092                 if (ttibn > 0) {        /* Success. */
6093                     x = 0;
6094                     break;
6095                 }
6096             }
6097         } else                          /* Timed case... */
6098 #endif /* LEBUF */
6099           {
6100 #ifdef NT_TCP_OVERLAPPED
6101             /* This code is for use on NT when we are using */
6102             /* Overlapped I/O to handle reads.  In the case */
6103             /* of outstanding reads select() doesn't work   */
6104
6105             if (WaitForOverlappedReadData(timo)) {
6106                 while (1) {
6107                     if (ttbufr() < 0)   /* Keep trying to refill it. */
6108                         break;          /* Till we get an error. */
6109                     if (ttibn > 0) {    /* Or we get a character. */
6110                         x = 0;
6111                         break;
6112                     }
6113                 }
6114             }
6115 #else /* NT_TCP_OVERLAPPED */
6116 #ifdef BSDSELECT
6117             fd_set rfds;
6118             struct timeval tv;
6119             int timeout = timo < 0 ? -timo : 1000 * timo;
6120             debug(F101,"netinc BSDSELECT","",timo);
6121
6122             for ( ; timeout >= 0; timeout -= (timo ? 100 : 0)) {
6123                 int rc;
6124                 debug(F111,"netinc","timeout",timeout);
6125                 /* Don't move select() initialization out of the loop. */
6126                 FD_ZERO(&rfds);
6127                 FD_SET(ttyfd, &rfds);
6128                 tv.tv_sec  = tv.tv_usec = 0L;
6129                 if (timo)
6130                   tv.tv_usec = (long) 100000L;
6131                 else
6132                   tv.tv_sec = 30;
6133 #ifdef NT
6134                 WSASafeToCancel = 1;
6135 #endif /* NT */
6136                 rc = select(FD_SETSIZE,
6137 #ifdef __DECC
6138 #ifdef INTSELECT
6139                             (int *)
6140 #else /* def INTSELECT */
6141                             (fd_set *)
6142 #endif /* def INTSELECT [else] */
6143 #else /* def __DECC */
6144                             (fd_set *)
6145 #endif /* def __DECC [else] */
6146                             &rfds, NULL, NULL, &tv);
6147                 if (rc < 0) {
6148                     int s_errno = socket_errno;
6149                     debug(F111,"netinc","select",rc);
6150                     debug(F111,"netinc","socket_errno",s_errno);
6151                     if (s_errno) {
6152 #ifdef OS2
6153                         ReleaseTCPIPMutex();
6154 #endif /* OS2 */
6155                         return(-1);
6156                     }
6157                 }
6158                 debug(F111,"netinc","select",rc);
6159 #ifdef NT
6160                 WSASafeToCancel = 0;
6161 #endif /* NT */
6162                 if (!FD_ISSET(ttyfd, &rfds)) {
6163 #ifdef LEBUF
6164                     if (le_inbuf() > 0) {
6165                         timeout = -1;
6166                         break;
6167                     }
6168 #endif /* LEBUF */
6169                     /* If waiting forever we have no way of knowing if the */
6170                     /* socket closed so try writing a 0-length TCP packet  */
6171                     /* which should force an error if the socket is closed */
6172                     if (!timo) {
6173                         if ((rc = socket_write(ttyfd,"",0)) < 0) {
6174                             int s_errno = socket_errno;
6175                             debug(F101,"netinc socket_write error","",s_errno);
6176 #ifdef OS2
6177                             if (os2socketerror(s_errno) < 0) {
6178                               ReleaseTCPIPMutex();
6179                               return(-2);
6180                             }
6181                             ReleaseTCPIPMutex();
6182 #endif /* OS2 */
6183                             return(-1); /* Call it an i/o error */
6184                         }
6185                     }
6186                     continue;
6187                 }
6188                 while (1) {
6189                     if (ttbufr() < 0) { /* Keep trying to refill it. */
6190                         timeout = -1;
6191                         break;          /* Till we get an error. */
6192                     }
6193                     if (ttibn > 0) {    /* Or we get a character. */
6194                         x = 0;
6195                         timeout = -1;
6196                         break;
6197                     }
6198                 }
6199             }
6200 #ifdef NT
6201             WSASafeToCancel = 0;
6202 #endif /* NT */
6203 #else /* !BSDSELECT */
6204 #ifdef IBMSELECT
6205 /*
6206   Was used by OS/2, currently not used, but might come in handy some day...
6207   ... and it came in handy!  For our TCP/IP layer, it avoids all the fd_set
6208   and timeval stuff since this is the only place where it is used.
6209 */
6210             int socket = ttyfd;
6211             int timeout = timo < 0 ? -timo : 1000 * timo;
6212
6213             debug(F101,"netinc IBMSELECT","",timo);
6214             for ( ; timeout >= 0; timeout -= (timo ? 100 : 0)) {
6215                 if (select(&socket, 1, 0, 0, 100L) == 1) {
6216                     while (1) {
6217                         if (ttbufr() < 0) { /* Keep trying to refill it. */
6218                             timeout = -1;
6219                             break;      /* Till we get an error. */
6220                         }
6221                         if (ttibn > 0) { /* Or we get a character. */
6222                             x = 0;
6223                             timeout = -1;
6224                             break;
6225                         }
6226                     }
6227                 }
6228 #ifdef LEBUF
6229                 else if (le_inbuf() > 0)  {
6230                     timeout = -1;
6231                     break;
6232                 }
6233 #endif /* LEBUF */
6234             }
6235 #else /* !IBMSELECT */
6236 #ifdef WINSOCK
6237        /* Actually, under WinSock we have a better mechanism than select() */
6238        /* for setting timeouts (SO_RCVTIMEO, SO_SNDTIMEO) */
6239             SOCKET socket = ttyfd;
6240             debug(F101,"netinc NTSELECT","",timo);
6241             if (setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, (char *)&timo,
6242                             sizeof(timo))  == NO_ERROR)
6243               while (1) {
6244                   if (ttbufr() < 0)     /* Keep trying to refill it. */
6245                     break;              /* Till we get an error. */
6246                   if (ttibn > 0) {      /* Or we get a character. */
6247                       x = 0;
6248                       break;
6249                   }
6250               }
6251 #else /* WINSOCK */
6252 /*
6253   If we can't use select(), then we use the regular alarm()/signal()
6254   timeout mechanism.
6255 */
6256             debug(F101,"netinc alarm","",timo);
6257             x = alrm_execute(ckjaddr(njbuf),timo,nettout,donetinc,failnetinc);
6258             ttimoff();                  /* Timer off. */
6259 #endif /* WINSOCK */
6260 #endif /* IBMSELECT */
6261 #endif /* BSDSELECT */
6262 #endif /* NT_TCP_OVERLAPPED */
6263         }
6264     }
6265
6266 #ifdef LEBUF
6267     if (le_inbuf() > 0) {               /* If data was inserted into the */
6268         if (le_getchar((CHAR *)&c) > 0) {/* Local Echo buffer while the   */
6269 #ifdef OS2                               /* was taking place do not mix   */
6270           ReleaseTCPIPMutex();           /* the le data with the net data */
6271 #endif /* OS2 */
6272           return(c);
6273         }
6274     }
6275 #endif /* LEBUF */
6276     if (x < 0) {                        /* Return -1 if we failed. */
6277         debug(F100,"netinc timed out","",0);
6278 #ifdef OS2
6279         ReleaseTCPIPMutex();
6280 #endif /* OS2 */
6281         return(-1);
6282     } else {                            /* Otherwise */
6283         c = ttibuf[ttibp];              /* Return the first char in ttibuf[] */
6284         if (deblog) {
6285 #ifndef COMMENT
6286             debug(F101,"netinc returning","",c);
6287 #endif /* COMMENT */
6288             if (c == 0) {
6289                 debug(F101,"netinc 0 ttibn","",ttibn);
6290                 debug(F101,"netinc 0 ttibp","",ttibp);
6291 #ifdef BETADEBUG
6292                 {
6293 #ifdef OS2
6294                     extern int tt_type_mode;
6295                     if ( !ISVTNT(tt_type_mode) )
6296 #endif /* OS2 */
6297                     ckhexdump("netinc &ttbuf[ttibp]",&ttibuf[ttibp],ttibn);
6298                 }
6299 #endif /* BETADEBUG */
6300             }
6301         }
6302         ttibp++;
6303         ttibn--;
6304 #ifdef OS2
6305         ReleaseTCPIPMutex();
6306 #endif /* OS2 */
6307 #ifdef CK_ENCRYPTION
6308         if (TELOPT_U(TELOPT_ENCRYPTION))
6309           ck_tn_decrypt(&c,1);
6310 #endif /* CK_ENCRYPTION */
6311         return(c);
6312     }
6313 #else /* Not using TCPIPLIB */
6314     return(-1);
6315 #endif /* TCPIPLIB */
6316 }
6317
6318 /*  N E T T O L  --  Output a string of bytes to the network  */
6319 /*
6320   Call with s = pointer to string, n = length.
6321   Returns number of bytes actually written on success, or
6322   -1 on i/o error, -2 if called improperly.
6323 */
6324
6325 int
6326 nettol(s,n) CHAR *s; int n; {
6327 #ifdef TCPIPLIB
6328     int count = 0;
6329     int len = n;
6330     int try = 0;
6331
6332     if (ttyfd == -1) {
6333         debug(F100,"nettol socket is closed","",0);
6334         return -1;
6335     }
6336     debug(F101,"nettol TCPIPLIB ttnet","",ttnet);
6337 #ifdef COMMENT
6338     ckhexdump("nettol",s,n);
6339 #endif /* COMMENT */
6340
6341 #ifdef CK_KERBEROS
6342 #ifdef KRB4
6343 #ifdef RLOGCODE
6344     if (ttnproto == NP_EK4LOGIN) {
6345         return(krb4_des_write(ttyfd,s,n));
6346     }
6347 #endif /* RLOGCODE */
6348 #endif /* KRB4 */
6349 #ifdef KRB5
6350 #ifdef RLOGCODE
6351     if (ttnproto == NP_EK5LOGIN) {
6352         return(krb5_des_write(ttyfd,s,n,0));
6353     }
6354 #endif /* RLOGCODE */
6355 #ifdef KRB5_U2U
6356     if (ttnproto == NP_K5U2U) {
6357         return(krb5_u2u_write(ttyfd,s,n));
6358     }
6359 #endif /* KRB5_U2U */
6360 #endif /* KRB5 */
6361 #endif /* CK_KERBEROS */
6362
6363 #ifdef CK_ENCRYPTION
6364     if (TELOPT_ME(TELOPT_ENCRYPTION))
6365       ck_tn_encrypt(s,n);
6366 #endif /* CK_ENCRYPTION */
6367
6368 #ifdef CK_SSL
6369     if (ssl_active_flag || tls_active_flag) {
6370         int error, r;
6371         /* Write using SSL */
6372       ssl_retry:
6373         if (ssl_active_flag)
6374           r = SSL_write(ssl_con, s, len /* >1024?1024:len */);
6375         else
6376           r = SSL_write(tls_con, s, len /* >1024?1024:len */);
6377         switch (SSL_get_error(ssl_active_flag?ssl_con:tls_con,r)) {
6378           case SSL_ERROR_NONE:
6379             debug(F111,"nettol","SSL_write",r);
6380             if ( r == len )
6381                 return(n);
6382              s += r;
6383              len -= r;
6384              goto ssl_retry;
6385           case SSL_ERROR_WANT_WRITE:
6386             debug(F100,"nettol SSL_ERROR_WANT_WRITE","",0);
6387             return(-1);
6388           case SSL_ERROR_WANT_READ:
6389             debug(F100,"nettol SSL_ERROR_WANT_READ","",0);
6390             return(-1);
6391           case SSL_ERROR_SYSCALL:
6392               if ( r == 0 ) { /* EOF */
6393                   netclos();
6394                   return(-2);
6395               } else {
6396                   int rc = -1;
6397 #ifdef NT
6398                   int gle = GetLastError();
6399                   debug(F111,"nettol SSL_ERROR_SYSCALL",
6400                          "GetLastError()",gle);
6401                   rc = os2socketerror(gle);
6402                   if (rc == -1)
6403                       rc = -2;
6404                   else if ( rc == -2 )
6405                       rc = -1;
6406 #endif /* NT */
6407                   return(rc);
6408               }
6409           case SSL_ERROR_WANT_X509_LOOKUP:
6410             debug(F100,"nettol SSL_ERROR_WANT_X509_LOOKUP","",0);
6411             netclos();
6412             return(-2);
6413           case SSL_ERROR_SSL:
6414             debug(F100,"nettol SSL_ERROR_SSL","",0);
6415               if (bio_err!=NULL) {
6416                   int len;
6417                   extern char ssl_err[];
6418                   BIO_printf(bio_err,"nettol() SSL_ERROR_SSL\n");
6419                   ERR_print_errors(bio_err);
6420                   len = BIO_read(bio_err,ssl_err,SSL_ERR_BFSZ);
6421                   ssl_err[len < SSL_ERR_BFSZ ? len : SSL_ERR_BFSZ] = '\0';
6422                   debug(F110,"nettol SSL_ERROR_SSL",ssl_err,0);
6423                   if (ssl_debug_flag)
6424                       printf(ssl_err);
6425               } else if (ssl_debug_flag) {
6426                   debug(F100,"nettol SSL_ERROR_SSL","",0);
6427                   fflush(stderr);
6428                   fprintf(stderr,"nettol() SSL_ERROR_SSL\n");
6429                   ERR_print_errors_fp(stderr);
6430               }
6431 #ifdef COMMENT
6432               netclos();
6433               return(-2);
6434 #else
6435               return(-1);
6436 #endif
6437           case SSL_ERROR_ZERO_RETURN:
6438             debug(F100,"nettol SSL_ERROR_ZERO_RETURN","",0);
6439             netclos();
6440             return(-2);
6441           default:
6442             debug(F100,"nettol SSL_ERROR_?????","",0);
6443             netclos();
6444             return(-2);
6445         }
6446     }
6447 #endif /* CK_SSL */
6448
6449   nettol_retry:
6450     try++;                              /* Increase the try counter */
6451
6452     if (ttnet == NET_TCPB) {
6453 #ifdef BSDSELECT
6454         fd_set wfds;
6455         struct timeval tv;
6456
6457         debug(F101,"nettol BSDSELECT","",0);
6458         tv.tv_usec = 0L;
6459         tv.tv_sec=30;
6460 #ifdef NT
6461         WSASafeToCancel = 1;
6462 #endif /* NT */
6463 #ifdef STREAMING
6464       do_select:
6465 #endif /* STREAMING */
6466         FD_ZERO(&wfds);
6467         FD_SET(ttyfd, &wfds);
6468         if (select(FD_SETSIZE, NULL,
6469 #ifdef __DECC
6470 #ifndef __DECC_VER
6471                     (int *)
6472 #endif /* __DECC_VER */
6473 #endif /* __DECC */
6474                    &wfds, NULL, &tv) < 0) {
6475             int s_errno = socket_errno;
6476             debug(F101,"nettol select failed","",s_errno);
6477 #ifdef BETADEBUG
6478             printf("nettol select failed: %d\n", s_errno);
6479 #endif /* BETADEBUG */
6480 #ifdef NT
6481             WSASafeToCancel = 0;
6482             if (!win95selectbug)
6483 #endif /* NT */
6484               return(-1);
6485         }
6486         if (!FD_ISSET(ttyfd, &wfds)) {
6487 #ifdef STREAMING
6488             if (streaming)
6489               goto do_select;
6490 #endif /* STREAMING */
6491             debug(F111,"nettol","!FD_ISSET",ttyfd);
6492 #ifdef NT
6493             WSASafeToCancel = 0;
6494             if (!win95selectbug)
6495 #endif /* NT */
6496               return(-1);
6497         }
6498 #ifdef NT
6499         WSASafeToCancel = 0;
6500 #endif /* NT */
6501 #else /* BSDSELECT */
6502 #ifdef IBMSELECT
6503         {
6504             int tries = 0;
6505             debug(F101,"nettol IBMSELECT","",0);
6506             while (select(&ttyfd, 0, 1, 0, 1000) != 1) {
6507                 int count;
6508                 if (tries++ >= 60) {
6509                     /* if after 60 seconds we can't get permission to write */
6510                     debug(F101,"nettol select failed","",socket_errno);
6511                     return(-1);
6512                 }
6513                 if ((count = nettchk()) < 0) {
6514                     debug(F111,"nettol","nettchk()",count);
6515                     return(count);
6516                 }
6517             }
6518         }
6519 #endif /* IBMSELECT */
6520 #endif /* BSDSELECT */
6521         if ((count = socket_write(ttyfd,s,n)) < 0) {
6522             int s_errno = socket_errno; /* maybe a function */
6523             debug(F101,"nettol socket_write error","",s_errno);
6524 #ifdef OS2
6525             if (os2socketerror(s_errno) < 0)
6526               return(-2);
6527 #endif /* OS2 */
6528             return(-1);                 /* Call it an i/o error */
6529         }
6530         if (count < n) {
6531             debug(F111,"nettol socket_write",s,count);
6532             if (try > 25) {
6533                 /* don't try more than 25 times */
6534                 debug(F100,"nettol tried more than 25 times","",0);
6535                 return(-1);
6536             }
6537             if (count > 0) {
6538                 s += count;
6539                 n -= count;
6540             }
6541             debug(F111,"nettol retry",s,n);
6542             goto nettol_retry;
6543         } else {
6544             debug(F111,"nettol socket_write",s,count);
6545             return(len); /* success - return total length */
6546         }
6547     } else
6548       return(-2);
6549 #else
6550     debug(F100,"nettol TCPIPLIB not defined","",0);
6551     return(-2);
6552 #endif /* TCPIPLIB */
6553 }
6554
6555 /*  N E T T O C  --   Output character to network */
6556 /*
6557   Call with character to be transmitted.
6558   Returns 0 if transmission was successful, or
6559   -1 upon i/o error, or -2 if called improperly.
6560 */
6561 int
6562 #ifdef CK_ANSIC
6563 nettoc(CHAR c)
6564 #else
6565 nettoc(c) CHAR c;
6566 #endif /* CK_ANSIC */
6567 /* nettoc */ {
6568 #ifdef UNIX
6569     return(ttoc(c));
6570 #else
6571 #ifdef TCPIPLIB
6572     unsigned char cc;
6573     if (ttyfd == -1) {
6574         debug(F100,"nettoc socket is closed","",0);
6575         return -1;
6576     }
6577     cc = c;
6578     debug(F101,"nettoc cc","",cc);
6579
6580 #ifdef CK_KERBEROS
6581 #ifdef KRB4
6582 #ifdef RLOGCODE
6583     if (ttnproto == NP_EK4LOGIN) {
6584         return(krb4_des_write(ttyfd,&cc,1)==1?0:-1);
6585     }
6586 #endif /* RLOGCODE */
6587 #endif /* KRB4 */
6588 #ifdef KRB5
6589 #ifdef RLOGCODE
6590     if (ttnproto == NP_EK5LOGIN) {
6591         return(krb5_des_write(ttyfd,&cc,1,0)==1?0:-1);
6592     }
6593 #endif /* RLOGCODE */
6594 #ifdef KRB5_U2U
6595     if (ttnproto == NP_K5U2U) {
6596         return(krb5_u2u_write(ttyfd,&cc,1)==1?0:-1);
6597     }
6598 #endif /* KRB5_U2U */
6599 #endif /* KRB5 */
6600 #endif /* CK_KERBEROS */
6601
6602 #ifdef CK_ENCRYPTION
6603         if ( TELOPT_ME(TELOPT_ENCRYPTION) )
6604             ck_tn_encrypt(&cc,1);
6605 #endif /* CK_ENCRYPTION */
6606 #ifdef CK_SSL
6607     if (ssl_active_flag || tls_active_flag) {
6608         int len, error;
6609         /* Write using SSL */
6610       ssl_retry:
6611         if (ssl_active_flag)
6612           len = SSL_write(ssl_con, &cc, 1);
6613         else
6614           len = SSL_write(tls_con, &cc, 1);
6615         switch (SSL_get_error(ssl_active_flag?ssl_con:tls_con,len)) {
6616           case SSL_ERROR_NONE:
6617             debug(F111,"nettoc","SSL_write",len);
6618             return(len == 1 ? 0 : -1);
6619           case SSL_ERROR_WANT_WRITE:
6620           case SSL_ERROR_WANT_READ:
6621             return(-1);
6622           case SSL_ERROR_SYSCALL:
6623               if ( len == 0 ) { /* EOF */
6624                   netclos();
6625                   return(-2);
6626               } else {
6627                   int rc = -1;
6628 #ifdef NT
6629                   int gle = GetLastError();
6630                   debug(F111,"nettoc SSL_ERROR_SYSCALL",
6631                          "GetLastError()",gle);
6632                   rc = os2socketerror(gle);
6633                   if (rc == -1)
6634                       rc = -2;
6635                   else if ( rc == -2 )
6636                       rc = -1;
6637 #endif /* NT */
6638                   return(rc);
6639               }
6640         case SSL_ERROR_SSL:
6641               if (bio_err!=NULL) {
6642                   int len;
6643                   extern char ssl_err[];
6644                   BIO_printf(bio_err,"nettoc() SSL_ERROR_SSL\n");
6645                   ERR_print_errors(bio_err);
6646                   len = BIO_read(bio_err,ssl_err,SSL_ERR_BFSZ);
6647                   ssl_err[len < SSL_ERR_BFSZ ? len : SSL_ERR_BFSZ] = '\0';
6648                   debug(F110,"nettoc SSL_ERROR_SSL",ssl_err,0);
6649                   if (ssl_debug_flag)
6650                       printf(ssl_err);
6651               } else if (ssl_debug_flag) {
6652                   debug(F100,"nettoc SSL_ERROR_SSL","",0);
6653                   fflush(stderr);
6654                   fprintf(stderr,"nettoc() SSL_ERROR_SSL\n");
6655                   ERR_print_errors_fp(stderr);
6656               }
6657               return(-1);
6658               break;
6659           case SSL_ERROR_WANT_X509_LOOKUP:
6660           case SSL_ERROR_ZERO_RETURN:
6661           default:
6662             netclos();
6663             return(-2);
6664         }
6665     }
6666 #endif /* CK_SSL */
6667     if (ttnet == NET_TCPB) {
6668 #ifdef BSDSELECT
6669         fd_set wfds;
6670         struct timeval tv;
6671
6672         debug(F101,"nettoc BSDSELECT","",0);
6673         tv.tv_usec = 0L;
6674         tv.tv_sec = 30;
6675
6676 #ifdef STREAMING
6677       do_select:
6678 #endif /* STREAMING */
6679
6680         FD_ZERO(&wfds);
6681         FD_SET(ttyfd, &wfds);
6682         if (select(FD_SETSIZE, NULL,
6683 #ifdef __DECC
6684 #ifndef __DECC_VER
6685                    (int *)
6686 #endif /* __DECC_VER */
6687 #endif /* __DECC */
6688                    &wfds, NULL, &tv) < 0) {
6689             int s_errno = socket_errno;
6690             debug(F101,"nettoc select failed","",s_errno);
6691 #ifdef BETADEBUG
6692             printf("nettoc select failed: %d\n", s_errno);
6693 #endif /* BETADEBUG */
6694 #ifdef NT
6695             WSASafeToCancel = 0;
6696             if (!win95selectbug)
6697 #endif /* NT */
6698               return(-1);
6699         }
6700         if (!FD_ISSET(ttyfd, &wfds)) {
6701 #ifdef STREAMING
6702             if (streaming)
6703               goto do_select;
6704 #endif /* STREAMING */
6705             debug(F111,"nettoc","!FD_ISSET",ttyfd);
6706 #ifdef NT
6707             WSASafeToCancel = 0;
6708             if (!win95selectbug)
6709 #endif /* NT */
6710               return(-1);
6711         }
6712 #ifdef NT
6713         WSASafeToCancel = 0;
6714 #endif /* NT */
6715 #else /* BSDSELECT */
6716 #ifdef IBMSELECT
6717         {
6718             int tries = 0;
6719             while (select(&ttyfd, 0, 1, 0, 1000) != 1) {
6720                 int count;
6721                 if (tries++ >= 60) {
6722                     /* if after 60 seconds we can't get permission to write */
6723                     debug(F101,"nettoc select failed","",socket_errno);
6724                     return(-1);
6725                 }
6726                 if ((count = nettchk()) < 0) {
6727                     debug(F111,"nettoc","nettchk()",count);
6728                     return(count);
6729                 }
6730             }
6731         }
6732 #endif /* IBMSELECT */
6733 #endif /* BSDSELECT */
6734         if (socket_write(ttyfd,&cc,1) < 1) {
6735             int s_errno = socket_errno;         /* maybe a function */
6736             debug(F101,"nettoc socket_write error","",s_errno);
6737 #ifdef OS2
6738             if (os2socketerror(s_errno) < 0)
6739               return(-2);
6740 #endif /* OS2 */
6741             return(-1);
6742         }
6743         debug(F101,"nettoc socket_write","", cc);
6744         return(0);
6745     } else return(-2);
6746 #else
6747     return(-2);
6748 #endif /* TCPIPLIB */
6749 #endif /* UNIX */
6750 }
6751
6752 /*  N E T F L U I  --  Flush network input buffer  */
6753
6754 #ifdef TNCODE
6755 static int
6756 #ifdef CK_ANSIC
6757 netgetc(int timo)                       /* Input function to point to... */
6758 #else  /* CK_ANSIC */
6759 netgetc(timo) int timo;
6760 #endif /* CK_ANSIC */
6761 {                                       /* ...in the tn_doop() call */
6762 #ifdef TCPIPLIB
6763     return netinc(timo);
6764 #else /* TCPIPLIB */
6765     return ttinc(timo);
6766 #endif /* TCPIPLIB */
6767 }
6768 #endif /* TNCODE */
6769
6770 int
6771 netflui() {
6772     int n;
6773     int ch;
6774 #ifdef NETLEBUF
6775     ttpush = -1;                        /* Clear the peek-ahead char */
6776     while (le_data && (le_inbuf() > 0)) {
6777         CHAR ch = '\0';
6778         if (le_getchar(&ch) > 0) {
6779             debug(F101,"ttflui le_inbuf ch","",ch);
6780         }
6781     }
6782 #endif /* NETLEBUF */
6783
6784 #ifdef TCPIPLIB
6785 #ifdef OS2
6786     RequestTCPIPMutex(SEM_INDEFINITE_WAIT);
6787 #endif /* OS2 */
6788 #ifdef TNCODE
6789     if (ttnproto == NP_TELNET) {
6790         /* Netflui must process Telnet negotiations or get out of sync */
6791         if ((n = nettchk()) <= 0)
6792           goto exit_flui;
6793         while (n-- > 0) {
6794             ch = netinc(1);
6795             if (ch == IAC) {
6796                 extern int duplex;  /* this really shouldn't be here but ... */
6797                 int tx = tn_doop((CHAR)(ch & 0xff),duplex,netgetc);
6798                 if (tx == 1) duplex = 1;
6799                 else if (tx == 2) duplex = 0;
6800                 n = nettchk();
6801             }
6802         }
6803     } else
6804 #endif /* TNCODE */
6805     {
6806         ttibuf[ttibp+ttibn] = '\0';
6807         debug(F111,"netflui 1",ttibuf,ttibn);
6808 #ifdef CK_ENCRYPTION
6809         if (TELOPT_U(TELOPT_ENCRYPTION)) {
6810             ck_tn_decrypt(&ttibuf[ttibp],ttibn);
6811         }
6812 #endif /* CK_ENCRYPTION */
6813         ttibn = ttibp = 0;              /* Flush internal buffer *FIRST* */
6814         if (ttyfd < 1)
6815           goto exit_flui;
6816         if ((n = nettchk()) > 0) {      /* Now see what's waiting on the net */
6817             if (n > TTIBUFL) n = TTIBUFL;       /* and sponge it up */
6818             debug(F101,"netflui 2","",n);       /* ... */
6819             n = socket_read(ttyfd,ttibuf,n); /* into our buffer */
6820             if (n >= 0) ttibuf[n] = '\0';
6821             debug(F111,"netflui 3",ttibuf,n);
6822 #ifdef CK_ENCRYPTION
6823             if (TELOPT_U(TELOPT_ENCRYPTION)) {
6824                 ck_tn_decrypt(&ttibuf[ttibp],n);
6825             }
6826 #endif /* CK_ENCRYPTION */
6827             ttibuf[0] = '\0';
6828         }
6829     }
6830 #else  /* !TCPIPLIB */
6831     if (ttyfd < 1)
6832       goto exit_flui;
6833 #ifdef TNCODE
6834     if (ttnproto == NP_TELNET) {
6835         if ((n = ttchk()) <= 0)
6836           goto exit_flui;
6837         while (n-- >= 0) {
6838             /* Netflui must process Telnet negotiations or get out of sync */
6839             ch = ttinc(1);
6840             if (ch == IAC) {
6841                 extern int duplex;  /* this really shouldn't be here but ... */
6842                 int tx = tn_doop((CHAR)(ch & 0xff),duplex,netgetc);
6843                 if (tx == 1) duplex = 1;
6844                 else if (tx == 2) duplex = 0;
6845                 n = ttchk();
6846             }
6847         };
6848     } else
6849 #endif /* TNCODE */
6850     if ((n = ttchk()) > 0) {
6851         debug(F101,"netflui non-TCPIPLIB","",n);
6852         while ((n--) && ttinc(1) > -1)  /* Don't worry, ttinc() is buffered */
6853           ;                             /* and it handles the decryption... */
6854     }
6855 #endif /* TCPIPLIB */
6856   exit_flui:
6857 #ifdef OS2
6858     ReleaseTCPIPMutex();
6859 #endif /* OS2 */
6860     return(0);
6861 }
6862
6863 #ifdef CK_KERBEROS
6864 /* The following two functions are required for encrypted rlogin */
6865 /* They are called with nettoc() or nettol() are transmitting    */
6866 /* encrypted data.  They call a function to encrypt the data     */
6867 /* and that function needs to be able to write to/read from the  */
6868 /* network in an unimpeded manner.  Hence, these two simple fns. */
6869 int
6870 net_write(fd, buf, len)
6871     int fd;
6872     register const char *buf;
6873     int len;
6874 {
6875     int cc;
6876     register int wrlen = len;
6877     do {
6878 #ifdef TCPIPLIB
6879         cc = socket_write(fd, buf, wrlen);
6880 #else
6881         cc = write(fd,buf,wrlen);
6882 #endif /* TCPIPLIB */
6883         if (cc < 0) {
6884             int s_errno = socket_errno;
6885             debug(F101,"net_write error","",s_errno);
6886 #ifdef OS2
6887             if (os2socketerror(s_errno) < 0)
6888                 return(-1);
6889             else
6890                 continue;
6891 #else /* OS2 */
6892             if (errno == EINTR)
6893                 continue;
6894             return(-1);
6895 #endif /* OS2 */
6896         }
6897         else {
6898             buf += cc;
6899             wrlen -= cc;
6900         }
6901     } while (wrlen > 0);
6902     return(len);
6903 }
6904 int
6905 net_read(fd, buf, len)
6906     int fd;
6907     register char *buf;
6908     register int len;
6909 {
6910     int cc, len2 = 0;
6911
6912     do {
6913 #ifdef TCPIPLIB
6914         cc = socket_read(fd, buf, len);
6915 #else
6916         cc = read(fd,buf,len);
6917 #endif
6918         if (cc < 0) {
6919             int s_errno = socket_errno;
6920             debug(F101,"net_read error","",s_errno);
6921 #ifdef OS2
6922             if (os2socketerror(s_errno) < 0)
6923                 return(-1);
6924 #endif /* OS2 */
6925             return(cc);          /* errno is already set */
6926         }
6927         else if (cc == 0) {
6928             netclos();
6929             return(len2);
6930         } else {
6931             buf += cc;
6932             len2 += cc;
6933             len -= cc;
6934         }
6935     } while (len > 0);
6936     return(len2);
6937 }
6938 #endif /* CK_KERBEROS */
6939 #endif /* NONET */
6940
6941 /* getlocalipaddr() attempts to resolve an IP Address for the local machine.
6942  *   If the host is multi-homed it returns only one address.
6943  *
6944  * Two techniques are used.
6945  * (1) get the local host name and perform a DNS lookup, then take
6946  *     the first entry;
6947  * (2) open a UDP socket, use it to connect to a fictitious host (it's OK,
6948  *    no data is sent), then retrieve the local address from the socket.
6949  * Note: the second technique won't work on Microsoft systems.  See
6950  * Article ID: Q129065 PRB: Getsockname() Returns IP Address 0.0.0.0 for UDP
6951  */
6952
6953 /* Technique number one cannot work reliably if the machine is a laptop
6954  * and the hostname is associated with a physical adapter which is not
6955  * installed and a PPP connection is being used instead.  This is because
6956  * the hostname DNS lookup will succeed for the physical adapter even though
6957  * it would be impossible to use it.  In NT4 SP4, the gethostbyname()
6958  * when given the result of gethostname() returns not the real DNS entries
6959  * for that name+domain.  Instead it returns all of the static and dynamic
6960  * IP addresses assigned to any physical or virtual adapter defined in the
6961  * system regardless of whether or not it is installed.  The order of the
6962  * addresses is fixed according to the binding order in the NT registry.
6963  */
6964
6965 /*
6966  * It appears that calling gethostbyname(NULL) is more reliable than
6967  * calling gethostbyname(gethostname()) on Windows.  So on Windows we will
6968  * only call gethostbyname(NULL).
6969  */
6970
6971 int
6972 getlocalipaddr() {
6973 #ifndef datageneral
6974     struct sockaddr_in l_sa;
6975     struct sockaddr_in r_sa;
6976     GSOCKNAME_T slen = sizeof(struct sockaddr_in);
6977     int sock;
6978     int rc;
6979     struct in_addr laddr;
6980
6981     /* if still not resolved, then try second strategy */
6982     /* This second strategy does not work on Windows */
6983
6984     debug(F100,"getlocalipaddr","",0);
6985     memset(&l_sa,0,slen);
6986     memset(&r_sa,0,slen);
6987
6988     /* get a UDP socket */
6989     sock = socket(AF_INET, SOCK_DGRAM, 0);
6990     if (sock != -1) {
6991         /* connect to arbirary port and address (NOT loopback) */
6992         r_sa.sin_family = AF_INET;
6993         r_sa.sin_port = htons(IPPORT_ECHO);
6994
6995         /* The following is an "illegal conversion" in AOS/VS */
6996         /* (and who knows where else) */
6997
6998 #ifdef INADDRX
6999         inaddrx = inet_addr("128.127.50.1");
7000         r_sa.sin_addr.s_addr = *(unsigned long *)&inaddrx;
7001 #else
7002         r_sa.sin_addr.s_addr = inet_addr("128.127.50.1");
7003 #endif /* INADDRX */
7004         rc = connect(sock, (struct sockaddr *) &r_sa, sizeof(struct sockaddr));
7005         if (!rc) {                      /* get local address */
7006             getsockname(sock,(struct sockaddr *)&l_sa,&slen);
7007 #ifdef TCPIPLIB
7008             socket_close(sock);         /* We're done with the socket */
7009 #else
7010             close(sock);
7011 #endif /* TCPIPLIB */
7012             if (l_sa.sin_addr.s_addr != INADDR_ANY) {
7013                 myxipaddr = ntohl(l_sa.sin_addr.s_addr);
7014                 ckstrncpy(myipaddr,(char *)inet_ntoa(l_sa.sin_addr),20);
7015                 debug(F110,"getlocalipaddr setting buf to",myipaddr,0);
7016                 return(0);
7017             }
7018         }
7019     }
7020     return getlocalipaddrs(myipaddr,sizeof(myipaddr),0);
7021 #else /* datageneral */
7022     return(-1);
7023 #endif /* datageneral */
7024 }
7025
7026 int
7027 getlocalipaddrs(buf,bufsz,index)
7028     char * buf;
7029     int    bufsz;
7030     int    index;
7031 /* getlocalipaddrs */ {
7032 #ifndef datageneral
7033     char localhost[256];
7034     struct hostent * host=NULL;
7035     struct sockaddr_in l_sa;
7036     struct sockaddr_in r_sa;
7037     GSOCKNAME_T slen = sizeof(struct sockaddr_in);
7038     int rc;
7039 #ifdef COMMENT
7040     int sock;
7041     char messageBuf[60];
7042     struct in_addr laddr;
7043 #endif /* COMMENT */
7044
7045     debug(F100,"getlocalipaddrs","",0);
7046     memset(&l_sa,0,slen);
7047     memset(&r_sa,0,slen);
7048
7049     /* init local address (to zero) */
7050     l_sa.sin_addr.s_addr = INADDR_ANY;
7051
7052 #ifdef CKGHNLHOST
7053     rc = gethostname(localhost, 256);
7054     debug(F110,"getlocalipaddrs localhost",localhost,0);
7055 #else
7056     /* This doesn't work on some platforms, e.g. Solaris */
7057     rc = 0;
7058     localhost[0] = '\0';
7059 #ifdef NT
7060     if ( winsock_version < 20 ) {
7061         rc = gethostname(localhost, 256);
7062         debug(F110,"getlocalipaddrs localhost",localhost,0);
7063     }
7064 #endif /* NT */
7065 #endif /* CKGHNLHOST */
7066     if (!rc) {
7067         /* resolve host name for local address */
7068         debug(F110,"getlocalipaddrs","calling gethostbyname()",0);
7069         host = gethostbyname(localhost);
7070         /* debug(F111,"getlocalipaddrs","gethostbyname() returned",host); */
7071         if (host) {
7072 #ifdef HADDRLIST
7073             host = ck_copyhostent(host);
7074             if ( index < 0 || index > 63 || !host->h_addr_list[index] ) {
7075                 buf[0] = '\0';
7076                 return(-1);
7077             }
7078             l_sa.sin_addr.s_addr =
7079               *((unsigned long *) (host->h_addr_list[index]));
7080             ckstrncpy(buf,(char *)inet_ntoa(l_sa.sin_addr),20);
7081             debug(F110,"getlocalipaddrs setting buf to",buf,0);
7082
7083 #ifdef COMMENT
7084             /* This is for reporting multiple IP Address */
7085             while (host->h_addr_list && host->h_addr_list[0]) {
7086                 l_sa.sin_addr.s_addr =
7087                   *((unsigned long *) (host->h_addr_list[0]));
7088                 ckstrncpy(messageBuf,
7089                         (char *)inet_ntoa(l_sa.sin_addr),60);
7090                 if (tcp_address) {
7091                     if (!strcmp(messageBuf,tcp_address))
7092                       ckstrncpy(myipaddr,tcp_address,20);
7093                 }
7094                 debug(F110,"getlocalipaddrs ip address list", messageBuf, 0);
7095                 host->h_addr_list++;
7096             }
7097 #endif /* COMMENT */
7098 #else   /* HADDRLIST */
7099             if (index != 0) {
7100                 buf[0] = '\0';
7101                 return(-1);
7102             }
7103             l_sa.sin_addr.s_addr = *((unsigned long *) (host->h_addr));
7104             ckstrncpy(buf,(char *)inet_ntoa(l_sa.sin_addr),bufsz);
7105             debug(F110,"getlocalipaddrs setting buf to",buf,0);
7106 #endif  /* HADDRLIST */
7107             return(0);
7108         } else debug(F110,
7109                      "getlocalipaddrs: gethostbyname() failed",
7110                      localhost,
7111                      0
7112                      );
7113     }
7114 #endif /* datageneral */
7115     return(-1);
7116 }
7117
7118 #ifdef RLOGCODE                 /* TCP/IP RLOGIN protocol support code */
7119 int
7120 rlog_naws() {
7121     struct rlog_naws {
7122         unsigned char id[4];
7123         unsigned short rows, cols, ypix, xpix;
7124     } nawsbuf;
7125
7126     if (ttnet != NET_TCPB)
7127       return 0;
7128     if (ttnproto != NP_RLOGIN
7129 #ifdef CK_KERBEROS
7130         && ttnproto != NP_K4LOGIN
7131         && ttnproto != NP_EK4LOGIN
7132         && ttnproto != NP_K5LOGIN
7133         && ttnproto != NP_EK5LOGIN
7134 #endif /* CK_KERBEROS */
7135          )
7136       return 0;
7137     if (!TELOPT_ME(TELOPT_NAWS))
7138       return 0;
7139
7140     debug(F100,"rlogin Window Size sent","",0);
7141
7142     nawsbuf.id[0] = nawsbuf.id[1] = 0377;
7143     nawsbuf.id[2] = nawsbuf.id[3] = 's';
7144 #ifdef OS2
7145     nawsbuf.rows = htons((unsigned short) (VscrnGetHeight(VTERM)
7146                           -(tt_status[VTERM]?1:0)));
7147     nawsbuf.cols = htons((unsigned short) VscrnGetWidth(VTERM));
7148 #else /* OS2 */
7149     nawsbuf.rows = htons((unsigned short) tt_rows);
7150     nawsbuf.cols = htons((unsigned short) tt_cols);
7151 #endif /* OS2 */
7152     nawsbuf.ypix = htons(0);            /* y pixels */
7153
7154     nawsbuf.xpix = htons(0);            /* x pixels */
7155     if (ttol((CHAR *)(&nawsbuf), sizeof(nawsbuf)) < 0)
7156       return(-1);
7157     return(0);
7158 }
7159
7160 #ifdef OS2ORUNIX
7161 #define RLOGOUTBUF
7162 #endif /* OS2 */
7163 static int
7164 #ifdef CK_ANSIC
7165 rlog_ini(CHAR * hostname, int port,
7166          struct sockaddr_in * l_addr, struct sockaddr_in * r_addr)
7167 #else /* CK_ANSIC */
7168 rlog_ini(hostname, port, l_addr, r_addr)
7169     CHAR * hostname;
7170     int port;
7171     struct sockaddr_in * l_addr;
7172     struct sockaddr_in * r_addr;
7173 #endif /* CK_ANSIC */
7174 /* rlog_ini */ {
7175
7176 #ifdef RLOGOUTBUF
7177     char outbuf[512];
7178     int  outbytes=0;
7179 #endif /* RLOGOUTBUF */
7180     int flag = 0;
7181 #define TERMLEN 16
7182 #define CONSPDLEN 16
7183     CHAR localuser[UIDBUFLEN+1];
7184     CHAR remoteuser[UIDBUFLEN+1];
7185     int userlen = 0;
7186     CHAR term_speed[TERMLEN+CONSPDLEN+1];
7187 #ifdef CONGSPD
7188     long conspd = -1L;
7189 #endif /* CONGSPD */
7190 #ifdef OS2
7191     extern int tt_type, max_tt;
7192     extern struct tt_info_rec tt_info[];
7193 #endif /* OS2 */
7194     int i, n;
7195
7196     int rc = 0;
7197     tn_reset();                 /* This call will reset all of the Telnet */
7198                                 /* options and then quit.  We need to do  */
7199                                 /* this since we use the Telnet options   */
7200                                 /* to hold various state information      */
7201     duplex = 0;                 /* Rlogin is always remote echo */
7202     rlog_inband = 0;
7203
7204 #ifdef CK_TTGWSIZ
7205 /*
7206   But compute the values anyway before the first read since the out-
7207   of-band NAWS request would arrive before the first data byte (NULL).
7208 */
7209 #ifdef OS2
7210     /* Console terminal screen rows and columns */
7211     debug(F101,"rlog_ini tt_rows 1","",VscrnGetHeight(VTERM)
7212            -(tt_status[VTERM]?1:0));
7213     debug(F101,"rlog_ini tt_cols 1","",VscrnGetWidth(VTERM));
7214     /* Not known yet */
7215     if (VscrnGetWidth(VTERM) < 0 ||
7216         VscrnGetHeight(VTERM)-(tt_status[VTERM]?1:0) < 0) {
7217         ttgwsiz();                      /* Try to get screen dimensions */
7218     }
7219     debug(F101,
7220           "rlog_ini tt_rows 2",
7221           "",
7222           VscrnGetHeight(VTERM)-(tt_status[VTERM]?1:0)
7223           );
7224     debug(F101,"rlog_ini tt_cols 2","",VscrnGetWidth(VTERM));
7225 #else /* OS2 */
7226     debug(F101,"rlog_ini tt_rows 1","",tt_rows);
7227     debug(F101,"rlog_ini tt_cols 1","",tt_cols);
7228     if (tt_rows < 0 || tt_cols < 0) {   /* Not known yet */
7229         ttgwsiz();                      /* Try to find out */
7230     }
7231     debug(F101,"rlog_ini tt_rows 2","",tt_rows);
7232     debug(F101,"rlog_ini tt_cols 2","",tt_cols);
7233 #endif /* OS2 */
7234 #endif /* CK_TTGWSIZ */
7235
7236     ttflui();                           /* Start by flushing the buffers */
7237
7238     rlog_mode = RL_COOKED;
7239
7240     /* Determine the user's local username ... */
7241
7242     localuser[0] = '\0';
7243 #ifdef NT
7244     {
7245         char localuid[UIDBUFLEN+1];
7246         ckstrncpy((char *)localuser,(char *)GetLocalUser(),UIDBUFLEN);
7247     }
7248
7249     if ( !localuser[0] )
7250 #endif /* NT */
7251     {
7252         char * user = getenv("USER");
7253         if (!user)
7254           user = "";
7255         userlen = strlen(user);
7256         debug(F111,"rlogin getenv(USER)",user,userlen);
7257         ckstrncpy((char *)localuser,user,UIDBUFLEN);
7258         debug(F110,"rlog_ini localuser 1",localuser,0);
7259     }
7260     if ( !localuser[0] )
7261         strcpy((char *)localuser,"unknown");
7262     else if (ck_lcname) {
7263         cklower((char *)localuser);
7264         debug(F110,"rlog_ini localuser 2",localuser,0);
7265     }
7266
7267     /* And the username to login with */
7268     if (uidbuf[0]) {
7269         ckstrncpy((char *)remoteuser,uidbuf,UIDBUFLEN);
7270         debug(F110,"rlog_ini remoteuser 1",remoteuser,0);
7271     } else if (localuser[0]) {
7272         ckstrncpy((char *)remoteuser,(char *)localuser,UIDBUFLEN);
7273         debug(F110,"rlog_ini remoteuser 2",remoteuser,0);
7274     } else {
7275         remoteuser[0] = '\0';
7276         debug(F110,"rlog_ini remoteuser 3",remoteuser,0);
7277     }
7278     if (ck_lcname)
7279       cklower((char *)remoteuser);
7280     debug(F110,"rlog_ini remoteuser 4",remoteuser,0);
7281
7282     /* The command to issue is the terminal type and speed */
7283     term_speed[0] = '\0';
7284     if (tn_term) {                      /* SET TELNET TERMINAL-TYPE value */
7285         if (*tn_term) {                 /* (if any) takes precedence. */
7286             ckstrncpy((char *)term_speed, tn_term, TERMLEN);
7287             flag = 1;
7288         }
7289     } else {                            /* Otherwise the local terminal type */
7290 #ifdef OS2
7291         /* In terminal-emulating versions, it's the SET TERM TYPE value */
7292         ckstrncpy(term_speed, (tt_type >= 0 && tt_type <= max_tt) ?
7293                 tt_info[tt_type].x_name : "network", TERMLEN);
7294 #else
7295         /* In the others, we just look at the TERM environment variable */
7296         {
7297             char *p = getenv("TERM");
7298             if (p)
7299               ckstrncpy((char *)term_speed,p,TERMLEN);
7300             else
7301               term_speed[0] = '\0';
7302 #ifdef VMS
7303             for (p = (char *) term_speed; *p; p++) {
7304                 if (*p == '-' && (!strcmp(p,"-80") || !strcmp(p,"-132")))
7305                   break;
7306                 else if (isupper(*p))
7307                   *p = tolower(*p);
7308             }
7309             *p = '\0';
7310 #endif /* VMS */
7311         }
7312 #endif /* OS2 */
7313     }
7314     n = strlen((char *)term_speed);
7315     if (n > 0) {                        /* We have a terminal type */
7316         if (!flag) {                    /* If not user-specified */
7317             for (i = 0; i < n; i++)     /* then lowercase it.    */
7318               if (isupper(term_speed[i]))
7319                 term_speed[i] = tolower(term_speed[i]);
7320         }
7321         debug(F110,"rlog_ini term_speed 1",term_speed,0);
7322
7323 #ifdef CONGSPD
7324         /* conspd() is not yet defined in all ck*tio.c modules */
7325         conspd = congspd();
7326         if (conspd > 0L) {
7327             ckstrncat((char *)term_speed,"/",sizeof(term_speed));
7328             ckstrncat((char *)term_speed,ckltoa(conspd),sizeof(term_speed));
7329         } else
7330 #endif /* CONGSPD */
7331           ckstrncat((char *)term_speed,"/19200",sizeof(term_speed));
7332         debug(F110,"rlog_ini term_speed 2",term_speed,0);
7333     } else {
7334         term_speed[0] = '\0';
7335         debug(F110,"rlog_ini term_speed 3",term_speed,0);
7336     }
7337
7338 #ifdef CK_KERBEROS
7339     if (ttnproto == NP_K4LOGIN || ttnproto == NP_EK4LOGIN ||
7340         ttnproto == NP_K5LOGIN || ttnproto == NP_EK5LOGIN) {
7341         int kver, encrypt, rc;
7342         switch (ttnproto) {
7343           case NP_K4LOGIN:
7344             kver = 4;
7345             encrypt = 0;
7346             break;
7347           case NP_EK4LOGIN:
7348             kver = 4;
7349             encrypt = 1;
7350             break;
7351           case NP_K5LOGIN:
7352             kver = 5;
7353             encrypt = 0;
7354             break;
7355           case NP_EK5LOGIN:
7356             kver = 5;
7357             encrypt = 1;
7358             break;
7359         default:
7360             kver = 0;
7361             encrypt = 0;
7362         }
7363         rc = ck_krb_rlogin(hostname, port,
7364                            localuser, remoteuser, term_speed,
7365                            l_addr, r_addr, kver, encrypt);
7366         if (!rc) {                      /* success */
7367             TELOPT_ME(TELOPT_NAWS) = 1;
7368             rc = rlog_naws();
7369         }
7370         return(rc);
7371     } else
7372 #endif /* CK_KERBEROS */
7373     if (ttnproto == NP_RLOGIN) {
7374 #ifdef RLOGOUTBUF
7375         /*
7376          *  The rcmds start the connection with a series of init data:
7377          *
7378          *    a port number upon which client is listening for stderr data
7379          *    the user's name on the client machine
7380          *    the user's name on the server machine
7381          *    the terminal_type/speed or command to execute
7382          */
7383         outbuf[outbytes++] = 0;
7384         strcpy((char *)outbuf+outbytes,(char *)localuser);
7385         outbytes += strlen((char *)localuser) + 1;
7386         strcpy((char *)outbuf+outbytes,(char *)remoteuser);
7387         outbytes += strlen((char *)remoteuser) + 1;
7388         strcpy((char *)outbuf+outbytes,(char *)term_speed);
7389         outbytes += strlen((char *)term_speed) + 1;
7390         rc = ttol((CHAR *)outbuf,outbytes);
7391 #else /* RLOGOUTBUF */
7392         ttoc(0);                        /* Send an initial NUL as wake-up */
7393         /* Send each variable with the trailing NUL */
7394         rc = ttol(localuser,strlen((char *)localuser)+1);
7395         if (rc > 0)
7396           rc = ttol(remoteuser,strlen((char *)remoteuser)+1);
7397         if (rc > 0)
7398           rc = ttol(term_speed,strlen((char *)term_speed)+1);
7399 #endif /* RLOGOUTBUF */
7400
7401         /* Now we are supposed to get back a single NUL as confirmation */
7402         errno = 0;
7403         rc = ttinc(60);
7404         debug(F101,"rlogin first ttinc","",rc);
7405         if (rc > 0) {
7406             debug(F101,"rlogin ttinc 1","",rc);
7407             printf(
7408                "Rlogin protocol error - 0x%x received instead of 0x00\n", rc);
7409             return(-1);
7410         } else if (rc < 0) {
7411             debug(F101,"rlogin ttinc errno","",errno);
7412             /* printf("Network error: %d\n", errno); */
7413             return(-1);
7414         }
7415     }
7416     return(0);
7417 }
7418
7419 /* two control messages are defined:
7420
7421    a double flag byte of 'o' indicates a one-byte message which is
7422    identical to what was once carried out of band.
7423
7424    a double flag byte of 'q' indicates a zero-byte message.  This
7425    message is interpreted as two \377 data bytes.  This is just a
7426    quote rule so that binary data from the server does not confuse the
7427    client.  */
7428
7429 int 
7430 rlog_ctrl(cp, n)
7431      unsigned char *cp;
7432      int n;
7433 {
7434     if ((n >= 5) && (cp[2] == 'o') && (cp[3] == 'o')) {
7435         if (rlog_oob(&cp[4],1))
7436             return(-5);
7437         return(5);
7438     } else if ((n >= 4) && (cp[2] == 'q') && (cp[3] == 'q')) {
7439         /* this is somewhat of a hack */
7440         cp[2] = '\377';
7441         cp[3] = '\377';
7442         return(2);
7443     }
7444     return(0);
7445 }
7446
7447 static int
7448 rlog_oob(oobdata, count) CHAR * oobdata; int count; {
7449     int i;
7450     int flush = 0;
7451
7452     debug(F111,"rlogin out_of_band","count",count);
7453
7454     for (i = 0; i<count; i++)   {
7455         debug(F101,"rlogin out_of_band","",oobdata[i]);
7456                 if (oobdata[i] & 0x01)
7457                         continue;
7458
7459         if (oobdata[i] & 0x02) { /* Flush Buffered Data not yet displayed */
7460             debug(F101,"rlogin Flush Buffered Data command","",oobdata[i]);
7461
7462             /* Only flush the data if in fact we are in a mode that won't */
7463             /* get out of sync.  Ie, not when we are in protocol mode.    */
7464             switch ( what ) {
7465             case W_NOTHING:
7466             case W_CONNECT:
7467             case W_COMMAND:
7468                 if ( rlog_inband )
7469                     flush = 1;
7470                 else
7471                     ttflui();
7472                 break;
7473             }
7474         }
7475         if (oobdata[i] & 0x10) {        /* Switch to RAW mode */
7476             debug(F101,"rlogin Raw Mode command","",oobdata[i]);
7477             rlog_mode = RL_RAW;
7478         }
7479
7480         if (oobdata[i] & 0x20) {        /* Switch to COOKED mode */
7481             debug(F101,"rlogin Cooked Mode command","",oobdata[i]);
7482             rlog_mode = RL_COOKED;
7483         }
7484         if (oobdata[i] & 0x80)
7485         {        /* Send Window Size Info */
7486             debug(F101,"rlogin Window Size command","",oobdata[i]);
7487             /* Remember to send WS Info when Window Size changes */
7488             if ( !TELOPT_ME(TELOPT_NAWS) ) {
7489                 TELOPT_ME(TELOPT_NAWS) = 1;
7490                 rlog_naws();
7491             }
7492         }
7493     }
7494     return(flush);
7495 }
7496 #ifndef TCPIPLIB
7497 static SIGTYP
7498 rlogoobh(sig) int sig; {
7499 #ifdef SOLARIS
7500     char                                /* Or should it be char for all? */
7501 #else
7502     CHAR
7503 #endif /* SOLARIS */
7504       oobdata;
7505
7506     /* int  count = 0; */ /* (not used) */
7507
7508     while (recv(ttyfd, &oobdata, 1, MSG_OOB) < 0) {
7509       /*
7510        * We need to do some special processing here.
7511        * Just in case the socket is blocked for input
7512        *
7513        */
7514         switch (errno) {
7515           case EWOULDBLOCK:
7516             break;
7517           default:
7518             return;
7519         }
7520     }
7521     debug(F101,"rlogin out_of_band","",oobdata);
7522     if (oobdata == 0x02) {      /* Flush Buffered Data not yet displayed */
7523         debug(F101,"rlogin Flush Buffered Data command","",oobdata);
7524         netflui();
7525     }
7526     if (oobdata & 0x10) {               /* Switch to raw mode */
7527         debug(F101,"rlogin Raw Mode command","",oobdata);
7528         rlog_mode = RL_RAW;
7529     }
7530     if (oobdata & 0x20) {               /* Switch to cooked mode */
7531         debug(F101,"rlogin Cooked Mode command","",oobdata);
7532         rlog_mode = RL_COOKED;
7533     }
7534     if (oobdata & 0x80) {                 /* Send Window Size Info */
7535         debug(F101,"rlogin Window Size command","",oobdata);
7536         /* Remember to send WS Info when Window Size changes */
7537         if ( !TELOPT_ME(TELOPT_NAWS) ) {
7538             TELOPT_ME(TELOPT_NAWS) = 1;
7539             rlog_naws();
7540         }
7541     }
7542 }
7543 #endif /* TCPIPLIB */
7544 #endif /* RLOGCODE */
7545
7546 /* Send network BREAK */
7547 /*
7548   Returns -1 on error, 0 if nothing happens, 1 if BREAK sent successfully.
7549 */
7550 int
7551 netbreak() {
7552     CHAR buf[3];
7553     if (ttnet == NET_TCPB) {
7554         if (ttnproto == NP_TELNET) {
7555 #ifdef TNCODE
7556             buf[0] = (CHAR) IAC; buf[1] = (CHAR) BREAK; buf[2] = (CHAR) 0;
7557             if (
7558 #ifdef OS2
7559                 nettol((char *) buf, 2)
7560 #else
7561                 ttol(buf, 2)
7562 #endif /* OS2 */
7563                 < 2)
7564               return(-1);
7565             if (tn_deb || debses || deblog) {
7566                 extern char tn_msg[];
7567                 ckmakmsg(tn_msg,TN_MSG_LEN,"TELNET SENT ",TELCMD(BREAK),
7568                           NULL,NULL);
7569                 debug(F101,tn_msg,"",BREAK);
7570                 if (debses || tn_deb) tn_debug(tn_msg);
7571             }
7572             return(1);
7573 #else
7574             debug(F100,"netbreak no TNCODE","",0);
7575             return(0);
7576 #endif /* TNCODE */
7577         }
7578         /* Insert other TCP/IP protocols here */
7579     }
7580     /* Insert other networks here */
7581     return(0);
7582 }
7583 #endif /* NETCONN */
7584
7585
7586 #ifdef NETCONN
7587 #ifdef SUNX25
7588 /*
7589   SunLink X.25 support by Marcello Frutig, Catholic University,
7590   Rio de Janeiro, Brazil, 1990.
7591 */
7592
7593 /* PAD X.3, X.28 and X.29 support */
7594
7595 static CHAR x29err[MAXPADPARMS+3] = { X29_ERROR, INVALID_PAD_PARM, '\0' };
7596
7597 /* Initialize PAD */
7598
7599 extern CHAR padparms[];
7600
7601 VOID
7602 initpad() {
7603   padparms[PAD_BREAK_CHARACTER]        = 0;  /* Break character */
7604   padparms[PAD_ESCAPE]                 = 1;  /* Escape permitted */
7605   padparms[PAD_ECHO]                   = 1;  /* Kermit PAD does echo */
7606   padparms[PAD_DATA_FORWARD_CHAR]      = 2;  /* forward character CR */
7607   padparms[PAD_DATA_FORWARD_TIMEOUT]   = 0;  /* no timeout forward condition */
7608   padparms[PAD_FLOW_CONTROL_BY_PAD]    = 0;  /* not used */
7609   padparms[PAD_SUPPRESSION_OF_SIGNALS] = 1;  /* allow PAD service signals */
7610   padparms[PAD_BREAK_ACTION]           = 21; /* brk action: INT pk + brk ind*/
7611   padparms[PAD_SUPPRESSION_OF_DATA]    = 0;  /* no supression of user data */
7612   padparms[PAD_PADDING_AFTER_CR]       = 0;  /* no padding after CR */
7613   padparms[PAD_LINE_FOLDING]           = 0;  /* no line fold */
7614   padparms[PAD_LINE_SPEED]             = 0;  /* line speed - don't care */
7615   padparms[PAD_FLOW_CONTROL_BY_USER]   = 0;  /* flow cont of PAD - not used */
7616   padparms[PAD_LF_AFTER_CR]            = 0;  /* no LF insertion after CR */
7617   padparms[PAD_PADDING_AFTER_LF]       = 0;  /* no padding after LF */
7618   padparms[PAD_EDITING]                = 1;  /* can edit */
7619   padparms[PAD_CHAR_DELETE_CHAR]       = 8;  /* character delete character */
7620   padparms[PAD_BUFFER_DELETE_CHAR]     = 21; /* buffer delete character */
7621   padparms[PAD_BUFFER_DISPLAY_CHAR]    = 18; /* buffer display character */
7622 }
7623
7624 /* Set PAD parameters */
7625
7626 VOID
7627 setpad(s,n) CHAR *s; int n; {
7628     int i;
7629     CHAR *ps = s;
7630
7631     if (n < 1) {
7632         initpad();
7633     } else {
7634         for (i = 0; i < n; i++) {
7635             if (*ps > MAXPADPARMS)
7636               x29err[i+2] = *ps;
7637             else
7638               padparms[*ps] = *(ps+1);
7639             ps += 2;
7640         }
7641     }
7642 }
7643
7644 /* Read PAD parameters */
7645
7646 VOID
7647 readpad(s,n,r) CHAR *s; int n; CHAR *r; {
7648     int i;
7649     CHAR *ps = s;
7650     CHAR *pr = r;
7651
7652     *pr++ = X29_PARAMETER_INDICATION;
7653     if (n > 0) {
7654         for (i = 0; i < n; i++, ps++) {
7655             if (*ps > MAXPADPARMS) {
7656                 x29err[i+2] = *ps++;
7657             } else {
7658                 *pr++ = *ps;
7659                 *pr++ = padparms[*ps++];
7660             }
7661         }
7662     } else {
7663         for (i = 1; i < MAXPADPARMS; i++) {
7664             *pr++ = i;
7665             *pr++ = padparms[i];
7666         }
7667     }
7668 }
7669
7670 int
7671 qbitpkt(s,n) CHAR *s; int n; {
7672     CHAR *ps = s;
7673     int x29cmd = *ps;
7674     CHAR *psa = s+1;
7675     CHAR x29resp[(MAXPADPARMS*2)+1];
7676
7677     switch (x29cmd) {
7678
7679         case X29_SET_PARMS:
7680             setpad (ps+1,n/2);
7681             if ((int)strlen((char *)x29err) > 2) {
7682                 ttol(x29err,(int)strlen((char *)x29err));
7683                 x29err[2] = '\0';
7684             }
7685             return (-2);
7686         case X29_READ_PARMS:
7687             readpad (ps+1,n/2,x29resp);
7688             setqbit ();
7689             ttol(x29resp,(n>1)?(n+1):(2*MAXPADPARMS+1));
7690             if ((int)strlen((char *)x29err) > 2) {
7691                 ttol(x29err,(int)strlen((char *)x29err));
7692                 x29err[2] = '\0';
7693             }
7694             resetqbit();
7695             break;
7696         case X29_SET_AND_READ_PARMS:
7697             setpad (ps+1,n/2);
7698             readpad (ps+1,n/2,x29resp);
7699             setqbit();
7700             ttol(x29resp,(n>1)?(n+1):(2*MAXPADPARMS+1));
7701             if ((int)strlen((char *)x29err) > 2) {
7702                 ttol (x29err,(int)strlen((char *)x29err));
7703                 x29err [2] = '\0';
7704             }
7705             resetqbit();
7706             return (-2);
7707         case X29_INVITATION_TO_CLEAR:
7708             (VOID) x25clear();
7709             return (-1);
7710         case X29_INDICATION_OF_BREAK:
7711             break;
7712     }
7713     return (0);
7714 }
7715
7716 /* PAD break action processor */
7717
7718 VOID
7719 breakact() {
7720     extern char x25obuf[MAXOX25];
7721     extern int obufl;
7722     extern int active;
7723     extern unsigned char tosend;
7724     static CHAR indbrk[3] = {
7725         X29_INDICATION_OF_BREAK,
7726         PAD_SUPPRESSION_OF_DATA,
7727         1
7728     };
7729     CHAR intudat, cause, diag;
7730
7731     if (x25stat() < 0) return;  /* Ignore if no virtual call established */
7732
7733     if (padparms[PAD_BREAK_ACTION] != 0) /* Forward condition */
7734         if (ttol((CHAR *)x25obuf,obufl) < 0) {
7735             perror ("\r\nCan't send characters");
7736             active = 0;
7737         } else {
7738             bzero (x25obuf,sizeof(x25obuf));
7739             obufl = 0;
7740             tosend = 0;
7741         };
7742
7743     switch (padparms[PAD_BREAK_ACTION]) {
7744
7745        case 0 : break;                  /* do nothing */
7746        case 1 : /* send interrupt packet with interrupt user data field = 1 */
7747                 intudat = 1;
7748                 x25intr (intudat);
7749                 break;
7750        case 2 : /* send reset packet with cause and diag = 0 */
7751                 cause = diag = 0;
7752                 x25reset (cause,diag);
7753                 break;
7754        case 5 : /* send interrupt packet with interrupt user data field = 0 */
7755                 intudat = 0;
7756                 x25intr (intudat);
7757                 setqbit ();
7758                 /* send indication of break without a parameter field */
7759                 ttoc(X29_INDICATION_OF_BREAK);
7760                 resetqbit ();
7761                 break;
7762        case 8 : active = 0;             /* leave data transfer */
7763                 conol ("\r\n");
7764                 break;
7765        case 21: /* send interrupt packet with interrupt user data field = 0 */
7766                 intudat = 0;
7767                 x25intr (intudat);
7768                 setpad (indbrk+1,2);    /* set pad to discard input */
7769                 setqbit ();
7770                 /* send indication of break with parameter field */
7771                 ttol (indbrk,sizeof(indbrk));
7772                 resetqbit ();
7773                 break;
7774      }
7775 }
7776
7777 /* X.25 support functions */
7778
7779 X25_CAUSE_DIAG diag;
7780
7781 /*
7782   Convert a null-terminated string representing an X.121 address
7783   to a packed BCD form.
7784 */
7785 int
7786 pkx121(str,bcd) char *str; CHAR *bcd; {
7787     int i, j;
7788     u_char c;
7789
7790     i = j = 0;
7791     while (str[i]) {
7792         if (i >= 15 || str [i] < '0' || str [i] > '9')
7793           return (-1);
7794         c = str [i] - '0';
7795         if (i & 1)
7796           bcd [j++] |= c;
7797         else
7798           bcd [j] = c << 4;
7799         i++;
7800     }
7801     return (i);
7802 }
7803
7804 /* Reads and prints X.25 diagnostic */
7805
7806 int
7807 x25diag () {
7808     int i;
7809
7810     bzero ((char *)&diag,sizeof(diag));
7811     if (ioctl(ttyfd,X25_RD_CAUSE_DIAG,&diag)) {
7812         perror ("Reading X.25 diagnostic");
7813         return(-1);
7814     }
7815     if (diag.datalen > 0) {
7816         printf ("X.25 Diagnostic :");
7817         for (i = 0; i < (int)diag.datalen; i++)
7818           printf(" %02h",diag.data[i])+
7819         printf ("\r\n");
7820     }
7821     return(0);
7822 }
7823
7824 /* X.25 Out-of-Band Signal Handler */
7825
7826 SIGTYP
7827 x25oobh(foo) int foo; {
7828     int oobtype;
7829     u_char oobdata;
7830     int t;
7831
7832     (VOID) signal(SIGURG,x25oobh);
7833     do {
7834         if (ioctl(ttyfd,X25_OOB_TYPE,&oobtype)) {
7835             perror ("Getting signal type");
7836             return;
7837         }
7838         switch (oobtype) {
7839           case INT_DATA:
7840             if (recv(ttyfd,(char *)&oobdata,1,MSG_OOB) < 0) {
7841                 perror ("Receiving X.25 interrupt data");
7842                 return;
7843             }
7844             t = oobdata;
7845             printf ("\r\nInterrupt received, data = %d\r\n", t);
7846             break;
7847           case VC_RESET:
7848             printf ("\r\nVirtual circuit reset\r\n");
7849             x25diag ();
7850             break;
7851           case N_RESETS:
7852             printf ("\r\nReset timeout\r\n");
7853             break;
7854           case N_CLEARS:
7855             printf ("\r\nClear timeout\r\n");
7856             break;
7857           case MSG_TOO_LONG:
7858             printf ("\r\nMessage discarded, too long\r\n");
7859             break;
7860           default:
7861             if (oobtype) printf("\r\nUnknown oob type %d\r\n",oobtype);
7862             break;
7863         }
7864     } while (oobtype);
7865 }
7866
7867 /* Send a X.25 interrupt packet */
7868
7869 int
7870 #ifdef CK_ANSIC
7871 x25intr(char intr)
7872 #else
7873 x25intr(intr) char intr;
7874 #endif /* CK_ANSIC */
7875 /* x25intr */ {
7876     if (send(ttyfd,&intr,1,MSG_OOB) < 0) return(-1);
7877     debug(F100,"X.25 intr","",0);
7878     return(0);
7879 }
7880
7881 /* Reset X.25 virtual circuit */
7882 int
7883 #ifdef CK_ANSIC
7884 x25reset(char cause, char diagn)
7885 #else
7886 x25reset(cause, diagn) char cause; char diagn;
7887 #endif /* CK_ANSIC */
7888 /* x25reset */ {
7889     bzero ((char *)&diag,sizeof(diag));
7890     diag.flags   = 0;
7891     diag.datalen = 2;
7892     diag.data[0] = cause;
7893     diag.data[1] = diagn;
7894     if (ioctl(ttyfd,X25_WR_CAUSE_DIAG,&diag) < 0)
7895       return(-1);
7896     debug(F100,"X.25 reset","",0);
7897     return(0);
7898 }
7899
7900 /* Clear X.25 virtual circuit */
7901 int
7902 x25clear() {
7903     int i;
7904     debug(F100,"X.25 clear","",0);
7905     bzero ((char *)&diag,sizeof(diag));
7906     diag.flags = (1 << DIAG_TYPE);
7907     diag.datalen = 2;
7908     diag.data[0] = 0;
7909     diag.data[1] = 0;
7910     ioctl (ttyfd,X25_WR_CAUSE_DIAG,&diag); /* Send Clear Request */
7911     return(ttclos(0));                  /* Close socket */
7912 }
7913
7914 /* X.25 status */
7915 int
7916 x25stat() {
7917     if (ttyfd == -1) return (-1);
7918     return(0);
7919 }
7920
7921 /* Set Q_BIT on */
7922 VOID
7923 setqbit() {
7924     static int qbiton = 1 << Q_BIT;
7925     ioctl (ttyfd,X25_SEND_TYPE,&qbiton);
7926 }
7927
7928 /* Set Q_BIT off */
7929 VOID
7930 resetqbit() {
7931     static int qbitoff = 0;
7932     ioctl (ttyfd,X25_SEND_TYPE,&qbitoff);
7933 }
7934
7935 /* Read n characters from X.25 circuit into buf */
7936
7937 int
7938 x25xin(n,buf) int n; CHAR *buf; {
7939     register int x, c;
7940     int qpkt;
7941
7942     do {
7943         x = read(ttyfd,buf,n);
7944         if (buf[0] & (1 << Q_BIT)) { /* If Q_BIT packet, process it */
7945             /* If return -1 : invitation to clear; -2 : PAD changes */
7946             if ((c=qbitpkt(buf+1,x-2)) < 0) return(c);
7947             qpkt = 1;
7948         } else qpkt = 0;
7949     } while (qpkt);
7950
7951 #ifdef COMMENT                  /* Disabled by Stephen Riehm 19.12.97 */
7952     /* BUG!
7953      * if buf[] is full, then this null lands in nirvana!
7954      * I was unable to find any code which needs a trailing null in buf[]
7955      */
7956     if (x > 0) buf[x] = '\0';
7957 #endif /* COMMENT */
7958     if (x < 1) x = -1;
7959     debug(F101,"x25xin x","",x);
7960
7961     return(x);
7962 }
7963
7964 #ifdef COMMENT /* NO LONGER NEEDED! */
7965 /* X.25 read a line */
7966
7967 int
7968 #ifdef PARSENSE
7969 #ifdef CK_ANSIC
7970 x25inl(CHAR *dest, int max,int timo, CHAR eol, CHAR start)
7971 #else
7972 x25inl(dest,max,timo,eol,start) int max,timo; CHAR *dest, eol, start;
7973 #endif /* CK_ANSIC */
7974 #else /* not PARSENSE */
7975 #ifdef CK_ANSIC
7976 x25inl(CHAR *dest, int max,int timo, CHAR eol)
7977 #else
7978 x25inl(dest,max,timo,eol) int max,timo; CHAR *dest, eol;
7979 #endif /* __SDTC__ */
7980 #endif /*PARSENSE */
7981  /* x25inl */ {
7982     CHAR *pdest;
7983     int pktype, goteol, rest, n;
7984     int i, flag = 0;
7985     extern int ttprty, ttpflg;
7986     int ttpmsk;
7987
7988     ttpmsk = (ttprty) ? 0177 : 0377;    /* Set parity stripping mask */
7989
7990     debug(F101,"x25inl max","",max);
7991     debug(F101,"x25inl eol","",eol);
7992     pdest  = dest;
7993     rest   = max;
7994     goteol = 0;
7995     do {
7996         n = read(ttyfd,pdest,rest);
7997         n--;
7998         pktype = *pdest & 0x7f;
7999         switch (pktype) {
8000           case 1 << Q_BIT:
8001             if (qbitpkt(pdest+1,--n) < 0) return(-2);
8002             break;
8003           default:
8004             if (flag == 0) { /* if not in packet, search start */
8005                 for (i = 1; (i < n) &&
8006                      !(flag = ((dest[i] & 0x7f) == start));
8007                      i++);
8008                 if (flag == 0) { /* not found, discard junk */
8009                     debug(F101,"x25inl skipping","",n);
8010                     continue;
8011                 } else {                /* found, discard junk before start */
8012                     int k;
8013                     n = n - i + 1;
8014                     for (k = 1; k <= n; k++, i++) dest[k] = dest[i];
8015                 }
8016             }
8017             for (i = 0; (i < n) && /* search for eol */
8018                  !(goteol=(((*pdest = *(pdest+1)&ttpmsk)&0x7f)== eol));
8019                  i++,pdest++);
8020             *pdest = '\0';
8021             rest -= n;
8022         }
8023     } while ((rest > 0) && (!goteol));
8024
8025     if (goteol) {
8026         n = max - rest;
8027         debug (F111,"x25inl X.25 got",(char *) dest,n);
8028         if (timo) ttimoff();
8029         if (ttpflg++ == 0 && ttprty == 0) {
8030             if ((ttprty = parchk(dest,start,n)) > 0) {
8031                 int j;
8032                 debug(F101,"x25inl senses parity","",ttprty);
8033                 debug(F110,"x25inl packet before",(char *)dest,0);
8034                 ttpmsk = 0x7f;
8035                 for (j = 0; j < n; j++)
8036                   dest[j] &= 0x7f; /* Strip parity from packet */
8037                 debug(F110,"x25inl packet after ",dest,0);
8038             } else {
8039                 debug(F101,"parchk","",ttprty);
8040                 if (ttprty < 0) { ttprty = 0; n = -1; }
8041             }
8042         }
8043         ttimoff();
8044         return(n);
8045     }
8046     ttimoff();
8047     return(-1);
8048 }
8049 #endif /* COMMENT */
8050 #endif /* SUNX25 */
8051
8052 #ifdef IBMX25
8053 /*
8054  * IBM X25 support - using the NPI streams interface
8055  * written by Stephen Riehm, pc-plus, Munich Germany
8056  */
8057
8058 /* riehm: missing functions / TODO list */
8059
8060 /*
8061   x25intr() - Send an interrupt packet
8062 */
8063
8064 /* return an error message depending on packet type */
8065 char *
8066 x25err(n) int n; {
8067     static char buf[30];
8068     switch (n) {
8069       case NBADADDR:     return "invalid address";
8070       case NBADOPT:      return "invalid options";
8071       case NACCESS:      return "no permission";
8072       case NNOADDR:      return "unable to allocate address";
8073       case NOUTSTATE:    return "invalid state";
8074       case NBADSEQ:      return "invalid sequence number";
8075       case NSYSERR:      return "system error";
8076       case NBADDATA:     return "invalid data size";
8077       case NBADFLAG:     return "invalid flag";
8078       case NNOTSUPPORT:  return "unsupported primitive";
8079       case NBOUND:       return "address in use";
8080       case NBADQOSPARAM: return "bad QOS parameters";
8081       case NBADQOSTYPE:  return "bad QOS type";
8082       case NBADTOKEN:    return "bad token value";
8083       case NNOPROTOID:   return "protocol id could not be allocated";
8084       case NODDCUD:      return "odd length call user data";
8085       default:
8086         ckmakmsg(buf,sizeof(buf),"Unknown NPI error ",ckitoa(n),NULL,NULL);
8087         return buf;
8088     }
8089 }
8090
8091 /* turn a meaningless primitive number into a meaningful primitive name */
8092 char *
8093 x25prim(n) int n; {
8094     static char buf[30];
8095     switch(n) {
8096       case N_BIND_ACK:     return "N_BIND_ACK";
8097       case N_BIND_REQ:     return "N_BIND_REQ";
8098       case N_CONN_CON:     return "N_CONN_CON";
8099       case N_CONN_IND:     return "N_CONN_IND";
8100       case N_CONN_REQ:     return "N_CONN_REQ";
8101       case N_CONN_RES:     return "N_CONN_RES";
8102       case N_DATACK_IND:   return "N_DATAACK_IND";
8103       case N_DATACK_REQ:   return "N_DATAACK_REQ";
8104       case N_DATA_IND:     return "N_DATA_IND";
8105       case N_DATA_REQ:     return "N_DATA_REQ";
8106       case N_DISCON_IND:   return "N_DISCON_IND";
8107       case N_DISCON_REQ:   return "N_DISCON_REQ";
8108       case N_ERROR_ACK:    return "N_ERROR_ACK";
8109       case N_EXDATA_IND:   return "N_EXDATA_IND";
8110       case N_EXDATA_REQ:   return "N_EXDATA_REQ";
8111       case N_INFO_ACK:     return "N_INFO_ACK";
8112       case N_INFO_REQ:     return "N_INFO_REQ";
8113       case N_OK_ACK:       return "N_OK_ACK";
8114       case N_OPTMGMT_REQ:  return "N_OPTMGMT_REQ";
8115       case N_RESET_CON:    return "N_RESET_CON";
8116       case N_RESET_IND:    return "N_RESET_IND";
8117       case N_RESET_REQ:    return "N_RESET_REQ";
8118       case N_RESET_RES:    return "N_RESET_RES";
8119       case N_UDERROR_IND:  return "N_UDERROR_IND";
8120       case N_UNBIND_REQ:   return "N_UNBIND_REQ";
8121       case N_UNITDATA_REQ: return "N_UNITDATA_REQ";
8122       case N_UNITDATA_IND: return "N_UNITDATA_IND";
8123       default:
8124         ckmakmsg(buf,sizeof(buf),"UNKNOWN (",ckitoa(n),")",NULL);
8125         return buf;
8126     }
8127 }
8128
8129 /*****************************************************************************
8130  * Function: x25getmsg()
8131  * Description: get a STREAMS message, and check it for errors
8132  *
8133  * Parameters:
8134  * fd           - file descriptor to x25 device (opened)
8135  * control      - control buffer (pre-allocated)
8136  * ctl_size     - size of control buffer
8137  * data         - data buffer (pre-allocated)
8138  * data_size    - size of data buffer
8139  * flags        - flags for getmsg()
8140  * expected     - expected Primitive type
8141  *
8142  * Return Value:
8143  *      >= 0    OK (size of data returned)
8144  *      -1      error
8145  *
8146  */
8147 int
8148 x25getmsg( fd, control, ctl_size, data, data_size, get_flags, expected )
8149     int                 fd;             /* X25 device (opened) */
8150     N_npi_ctl_t         *control;       /* control buffer (pre-allocated) */
8151     int                 ctl_size;       /* size of control buffer */
8152     N_npi_data_t        *data;          /* data buffer (pre-allocated) */
8153     int                 data_size;      /* size of data buffer */
8154     int                 *get_flags;     /* getmsg() flags */
8155     int                 expected;       /* expected primitive type */
8156 /* x25getmsg */ {
8157     int                 rc = 0;         /* return code */
8158     struct strbuf       *get_ctl=NULL;  /* getmsg control */
8159     struct strbuf       *get_data=NULL; /* getmsg data */
8160     int                 more = 0;       /* flag for more data etc */
8161     int                 file_status = -1; /* file async status */
8162     N_npi_ctl_t         * result;       /* pointer to simplify switch() */
8163     int                 packet_type = -1; /* unknown packet thus far */
8164
8165 #ifdef TRACE
8166     printf( "TRACE: entering x25getmsg\n" );
8167 #endif /* TRACE */
8168
8169     debug( F110, "x25getmsg waiting for packet ", x25prim( expected ), 0);
8170     /* prepare the control structures for getmsg */
8171     if (control) {
8172         if ((get_ctl = (struct strbuf*)malloc(sizeof(struct strbuf))) == NULL)
8173           {
8174               perror("kermit x25getmsg(): get_ctl malloc failed\n");
8175               debug( F100, "x25getmsg malloc failed for get_ctl\n", "", 0);
8176               return(-1);
8177           }
8178         /* allow getmsg to return an unexpected packet type (which may be
8179          * larger than the expected one)
8180          */
8181         get_ctl->maxlen = NPI_MAX_CTL;
8182         get_ctl->len = 0;
8183         get_ctl->buf = (char *)control;
8184     } else {
8185         printf(
8186  "kermit x25getmsg(): internal error. control buffer MUST be pre-allocated!\n"
8187                );
8188         debug(F100,"x25getmsg internal error. no buffer pre-allocated","",0);
8189         return( -1 );
8190     }
8191     if (data) {
8192         if ((get_data = (struct strbuf*)malloc(sizeof(struct strbuf))) == NULL)
8193           {
8194             perror("kermit x25getmsg(): get_data malloc failed\n");
8195             debug( F100, "x25getmsg malloc failed for get_data\n", "", 0);
8196             return(-1);
8197         }
8198         get_data->maxlen = (NPI_MAX_DATA < data_size ) ?
8199           NPI_MAX_DATA :
8200             data_size;
8201         get_data->len = 0;
8202         get_data->buf = (char *)data;
8203     }
8204
8205     /* get an X.25 packet -
8206      * it may be any kind of packet, so check for special cases
8207      * it may be split into multiple parts - so loop if necessary
8208      */
8209     do {
8210 #ifdef DEBUG
8211         printf( "kermit: x25getmsg(): getting a message\n" );
8212 #endif /* DEBUG */
8213         errno = 0;
8214         if ((more = getmsg(fd, get_ctl, get_data, get_flags)) < 0) {
8215 #ifdef DEBUG
8216             printf( "kermit: x25getmsg(): getmsg returned an error\n" );
8217             perror( "getmsg error was" );
8218 #endif /* DEBUG */
8219             debug(F101, "x25getmsg getmsg returned an error\n", "", errno);
8220             if ((errno == EAGAIN) && (get_data && (get_data->len > 0)) ) {
8221                 /* was in non-blocking mode, nothing to get, but we're
8222                  * already waiting for the rest of the packet -
8223                  * switch to blocking mode for the next read.
8224                  * file_status used to reset file status before returning
8225                  */
8226                 if ((file_status = fcntl(fd, F_GETFL, 0)) < 0
8227                     || fcntl(fd, F_SETFL, file_status & ~O_NDELAY) < 0)
8228                   {
8229                       perror("x25getmsg(): couldn't change x25 blocking mode");
8230                       debug(F101,
8231                             "x25getmsg fcntl returned an error\n", "", errno);
8232                       /* netclos(); */
8233                       rc = -1;
8234                       break;
8235                   } else {
8236                       /* loop again into a blocking getmsg() */
8237                       continue;
8238                   }
8239             } else {
8240                 /* no data to get in non-blocking mode - return empty handed */
8241                 perror( "x25getmsg(): getmsg failed" );
8242                 debug(F101,"x25getmsg getmsg returned an error\n", "", errno);
8243                 rc = -1;
8244                 break;
8245             }
8246         } else if (more & MORECTL) {
8247             /* panic - the control information was larger than the
8248              * maximum control buffer size!
8249              */
8250             /* riehm: close connection? */
8251 #ifdef DEBUG
8252             printf("x25getmsg(): received partial control packet - panic\n");
8253 #endif /* DEBUG */
8254             debug( F101, "x25getmsg getmsg bad control block\n", "", errno);
8255             rc = -1;
8256             break;
8257         }
8258
8259         if (result = (N_npi_ctl_t *)control) {
8260             packet_type = result->bind_ack.PRIM_type;
8261             if (packet_type != N_OK_ACK) {
8262                 x25lastmsg = packet_type;
8263             }
8264         }
8265 #ifdef DEBUG
8266         /* printf( "kermit: x25getmsg(): getting " ); */
8267         if (get_ctl->len > 0) {
8268             x25dump_prim(result);
8269         }
8270         debug(F110,
8271               "x25getmsg got packet ",
8272               x25prim( result->bind_ack.PRIM_type ),
8273               0
8274               );
8275 #endif /* DEBUG */
8276
8277         if (get_ctl->len >= (int)sizeof(result->bind_ack.PRIM_type)) {
8278             /* not as pretty as a switch(), but switch can't handle
8279              * runtime variable values :-(
8280              */
8281             if (packet_type == expected ) {
8282                 /* got what we wanted, special case for DATA_IND
8283                  * packets though */
8284                 /* riehm: check Q-bit ? */
8285 #ifdef DEBUG
8286                 printf("x25getmsg(): got expected packet\nrc is %d\n", rc);
8287 #endif /* DEBUG */
8288                 if (packet_type == N_DATA_IND ) {
8289                     /* data received. May be incomplete, even though
8290                      * getmsg returned OK
8291                      */
8292                     if (result->data_ind.DATA_xfer_flags & N_MORE_DATA_FLAG)
8293                         more |= MOREDATA;
8294                     if (result->data_ind.DATA_xfer_flags & N_RC_FLAG)
8295                         printf( "x25getmsg(): data packet wants ack\n" );
8296                 }
8297             } else if( packet_type == N_DISCON_IND) {
8298                 printf( "X25 diconnected\n" );
8299                 /* riehm: need to acknowledge a disconnection? */
8300                 x25clear();
8301                 /* x25unbind( ttyfd ); */
8302                 rc = -1;
8303             } else if( packet_type == N_ERROR_ACK) {
8304                 errno = result->error_ack.UNIX_error;
8305                 perror( "X25 error received" );
8306                 rc = -1;
8307             } else {
8308                 printf("x25getmsg(): failed %s\n", x25err(packet_type));
8309                 rc = -1;
8310             }
8311         }
8312 #ifdef COMMENT
8313         else {
8314             /* Panic - no control data */
8315             printf( "kermit: x25getmsg(): no control data with packet\n" );
8316             rc = -1;
8317         }
8318 #endif /* COMMENT */
8319
8320         if (get_data && (get_data->len >= 0)) {
8321             get_data->buf += get_data->len;
8322             get_data->maxlen -= get_data->len;
8323         }
8324     } while ((rc == 0)
8325              && (get_data && (get_data->maxlen > 0))
8326              && (more & MOREDATA)
8327              );
8328
8329     /* return the file status to its original value, unless its still
8330      * set to -1, or one of the fcntl's failed */
8331     if ((file_status >= 0) && fcntl(fd, F_SETFL, file_status) < 0)
8332         rc = -1;
8333
8334     /*
8335      * Verify that we received an expected primitive
8336      * there is apparantly an error case where the primitive is set
8337      * correctly, but there is not enough data in the control structure
8338      */
8339     if ((packet_type != expected) && (get_ctl->len >= ctl_size) ) {
8340         fprintf(stderr,
8341                 "x25getmsg(): %s NOT received. Primitive received was %s\n",
8342                 x25prim( expected ), x25prim( packet_type ));
8343         debug(F110, "x25getmsg got an unexpected packet ",
8344               x25prim(packet_type),
8345               0
8346               );
8347         rc = -1;
8348     }
8349
8350     if (rc == 0) {
8351         if (get_data && ( get_data->len >= 0)) {
8352             rc = get_data->len;
8353         }
8354     }
8355
8356     if (get_ctl)  { free(get_ctl); get_ctl = NULL; }
8357     if (get_data) { free(get_data); get_data = NULL; }
8358
8359 #ifdef COMMENT
8360 #ifdef DEBUG
8361     printf( "kermit x25getmsg(): returning %d\n", rc );
8362 #endif /* DEBUG */
8363 #endif /* COMMENT */
8364     debug(F110, "x25getmsg returning packet ", x25prim( packet_type ), 0);
8365
8366 #ifdef TRACE
8367     printf( "TRACE: leaving x25getmsg\n" );
8368 #endif /* TRACE */
8369     return(rc);
8370 }
8371
8372 /*****************************************************************************
8373  * Function: x25putmsg()
8374  *
8375  * Description:
8376  *      send a message to a X25 STREAM
8377  *
8378  * Parameters:
8379  *      fd              - file descriptor to x25 device (opened)
8380  *      control         - control buffer (pre-allocated)
8381  *      data            - data buffer (pre-allocated)
8382  *      data_len        - length of data to be transmitted
8383  *      put_flags       - flags for putmsg()
8384  *
8385  * Return Value:
8386  *      >= 0    number of bytes transmitted
8387  *      -1      error
8388  */
8389 int
8390 x25putmsg(fd, control, data, data_len, put_flags)
8391     int                 fd;             /* X25 device (opened) */
8392     N_npi_ctl_t         *control;       /* control buffer (pre-allocated) */
8393     N_npi_data_t        *data;          /* data buffer (pre-allocated) */
8394     int                 data_len;       /* length of data (not the size of
8395                                            the buffer) */
8396     int                 *put_flags;     /* putmsg() flags */
8397 /* x25putmsg */ {
8398     int                 rc = 0;         /* return code */
8399     ulong               type;           /* primitive type */
8400     struct strbuf       *put_ctl = NULL; /* putmsg control */
8401     struct strbuf       *put_data = NULL; /* putmsg data */
8402
8403 #ifdef TRACE
8404     printf( "TRACE: entering x25putmsg\n" );
8405 #endif /* TRACE */
8406
8407 #ifdef DEBUG
8408     printf( "kermit: x25putmsg(): putting " );
8409     x25dump_prim( control );
8410     printf( "\tdata:\t\t" );
8411     x25dump_data( data, 0, data_len );
8412     debug(F110,"x25putmsg: putting packet ",x25prim(control->PRIM_type),0);
8413 #endif /* DEBUG */
8414
8415     if (control) {
8416         put_ctl = (struct strbuf *)malloc( sizeof( struct strbuf ) );
8417         if (put_ctl == NULL) {
8418             perror("kermit x25putmsg(): put_ctl malloc failed\n");
8419             return(-1);
8420         }
8421         put_ctl->maxlen = 0;                    /* unused by putmsg */
8422         put_ctl->len = NPI_MAX_CTL;
8423         put_ctl->buf = (char *)control;
8424     }
8425     if (data && ( data_len > 0)) {
8426         put_data = (struct strbuf *)malloc( sizeof( struct strbuf ) );
8427         if( put_data == NULL) {
8428             perror("kermit x25putmsg(): put_data malloc failed\n");
8429             return(-1);
8430         }
8431         put_data->maxlen = 0;                   /* unused by putmsg */
8432         put_data->len = data_len;
8433         put_data->buf = (char *)data;
8434     }
8435
8436     errno = 0;
8437     rc = putmsg (fd, put_ctl, put_data, 0);
8438     if (rc < 0) {
8439         printf("x25putmsg(): couldn't put %s\n",x25prim(control->PRIM_type));
8440         perror("kermit: x25putmsg(): putmsg failed");
8441         return(-1);
8442     }
8443
8444     /* riehm: this should perhaps be discounted! */
8445     x25lastmsg = control->PRIM_type;
8446
8447 #ifdef COMMENT
8448 #ifdef DEBUG
8449     printf( "kermit debug: x25putmsg() returning %d\n", data_len );
8450 #endif /* DEBUG */
8451 #endif /* COMMENT */
8452     debug( F101, "x25putmsg block size put ", "", data_len);
8453
8454 #ifdef TRACE
8455     printf( "TRACE: leaving x25putmsg\n" );
8456 #endif /* TRACE */
8457
8458     return( data_len );
8459 }
8460
8461 /*****************************************************************************
8462 * Function: x25bind
8463 * Description:  The bind submitted to NPI provides the information required
8464 *               by the packet layer for it to listen for suitable incoming
8465 *               calls.
8466 *
8467 * WARNING:
8468 *
8469 * This routine needs to be called in a completely different manner for
8470 * the client and server side. When starting a client, the
8471 * num_waiting_calls and CUD information should all be set to 0! The
8472 * client's CUD must be inserted in the CONN_REQ data block.
8473 * When starting a server, the CUD must be set to a CUD pattern, and
8474 * the number of waiting calls should be set to a number other than 0.
8475 * (num waiting calls is the number of incomming calls which are to be
8476 * put on hold while the server is servicing another client.)
8477 *
8478 * Who invented this crap?
8479 *
8480 * Parameters:
8481 *       fd              - X25 device (opened)
8482 *       addr            - local address
8483 *       cud             - User Data (null terminated)
8484 *       cud_len         - User Data length
8485 *       num_waiting_calls - number of outstanding calls allowed on this stream
8486 *       line            - logical port number (1)
8487 *       flags           - 0, DEFAULT_LISTENER or TOKEN_REQUEST
8488 *
8489 * Return Value:
8490 *       if binding is successful, 0 is returned for a client, and a token is
8491 *       returned for a server
8492 *
8493 * Return code: 0 if successful
8494 *              -1 if unsuccessful
8495 *****************************************************************************/
8496
8497 ulong
8498 x25bind(fd, addr, cud, cud_len, num_waiting_calls, line, bind_flags)
8499     int fd;                             /* X25 device (opened) */
8500     char * addr;                        /* local address */
8501     char * cud;                         /* Call User Data (null terminated) */
8502     int cud_len;                        /* User Data length */
8503     int num_waiting_calls;              /* Outstanding calls allowed */
8504     int line;                           /* logical port number */
8505     ulong bind_flags;           /* 0, DEFAULT_LISTENER or TOKEN_REQUEST */
8506 /* x25bind */ {
8507     ulong rc;                           /* return code */
8508     int get_flags;                      /* priority flag passed to getmsg */
8509     int put_flags = 0;                  /* output flags for putmsg, always 0 */
8510     ulong type;                         /* primitive type */
8511     N_bind_req_t *bind_req;             /* pointer to N_BIND_REQ primitive */
8512     N_bind_ack_t *bind_ack;             /* pointer to N_BIND_ACK primitive */
8513     char *addtl_info;                   /* pointer to info in addition to
8514                                          * the N_BIND_REQ primitive that is
8515                                          * passed in the control structure
8516                                          * to putmsg */
8517     int addr_len = 0;                   /* length of address string */
8518     ulong bind_req_t_size;              /* for debugging only */
8519
8520 #ifdef TRACE
8521     printf("TRACE: entering x25bind\n" );
8522 #endif /* TRACE */
8523
8524 #ifdef DEBUG
8525     printf("TRACE: x25bind( %d, %s, %s, %d, %d )\n",
8526            fd, addr, cud, line, bind_flags
8527            );
8528 #endif /* DEBUG */
8529
8530     /*
8531      * Allocate  and zero out space to hold the control portion of the
8532      * message passed to putmsg. This will contain the N_BIND_REQ
8533      * primitive and any additional info required for that.
8534      *
8535      * Note: allocated space is the size of the union typedef
8536      * N_npi_ctl_t to allow the use fo the generic x25putmsg routine.
8537      */
8538     bind_req = (N_bind_req_t *) malloc(sizeof( N_npi_ctl_t));
8539     if (bind_req == NULL) {
8540         perror("kermit: x25bind(): bind_req malloc failed");
8541         debug(F100, "x25bind bind_req malloc failed", "", 0);
8542         return(-1);
8543     }
8544     bzero((char *)bind_req, sizeof(N_npi_ctl_t));
8545
8546     /* Build the Bind Request Primitive */
8547     bind_req->PRIM_type = (ulong) N_BIND_REQ;
8548
8549     /* Note that the address length is n+2 and NOT n. Two bytes MUST preceed
8550      * the actual address in an N_BIND_REQ. The first byte contains the
8551      * line number being used with this address, and the second byte is the
8552      * X.121 address prefix, which must be zero.
8553      */
8554     addr_len = strlen(addr);
8555     bind_req->ADDR_length = (ulong) (addr_len + 2);
8556     bind_req->ADDR_offset = (ulong)(sizeof(N_bind_req_t));
8557     bind_req->CONIND_number = (ulong)num_waiting_calls; /* server only */
8558     bind_req->BIND_flags = (ulong) bind_flags; /* 0 in client */
8559     bind_req->PROTOID_length = (ulong) cud_len; /* 0 in client */
8560     if (cud_len == 0) {
8561         bind_req->PROTOID_offset = (ulong) 0;
8562     } else {
8563         /* need to remember the trailing NULL in the address - not
8564          * counted in the address length
8565          */
8566         bind_req->PROTOID_offset
8567           = (ulong) (sizeof(N_bind_req_t) + bind_req->ADDR_length);
8568     }
8569
8570     /*
8571      * Now fill in the additional information required with this primitive
8572      * (address and protocol information (Call User Data))
8573      */
8574     addtl_info = (char *) ((void *)bind_req + bind_req->ADDR_offset);
8575     /*
8576      * The bitwise "&" ensures that the line number is only one byte long
8577      */
8578     *addtl_info++ = (char) line & 0xff;
8579     *addtl_info++ = (char) 0; /* X.121 format */
8580     bcopy( addr, addtl_info, addr_len ); /* include trailing null */
8581     addtl_info += addr_len;
8582     if (cud_len > 0)
8583       bcopy( cud, addtl_info, cud_len );
8584     /*
8585      * Call putmsg() to put the bind request message on the stream
8586      */
8587     if (x25putmsg(fd,
8588                   (N_npi_ctl_t*)bind_req,
8589                   (N_npi_data_t *)NULL,
8590                   0,
8591                   &put_flags
8592                   ) < 0) {
8593         printf( "kermit: x25bind(): x25putmsg failed\n" );
8594         return(-1);
8595     }
8596
8597     /*
8598      * Allocate and zero out space for the N_BIND_ACK primitive
8599      */
8600     bind_ack = (N_bind_ack_t *) malloc(sizeof(N_npi_ctl_t));
8601     if (bind_ack == NULL){
8602         perror("kermit: x25bind(): bind_ack malloc failed");
8603         return(-1);
8604     }
8605     bzero(bind_ack, sizeof(N_npi_ctl_t));
8606     /*
8607      * Initialize the control structure and flag variable sent to getmsg
8608      */
8609     get_flags=0;
8610
8611     /* get the ACK for the bind */
8612 #ifdef DEBUG
8613     printf( "kermit: x25bind() trying to get a BIND_ACK\n" );
8614 #endif /* DEBUG */
8615     rc = (ulong)x25getmsg( fd, (N_npi_ctl_t*)bind_ack,
8616             (int)sizeof( N_bind_ack_t ), (N_npi_data_t*)NULL, 0, &get_flags,
8617             N_BIND_ACK );
8618
8619     /* turn quantitive return code into a qualitative one */
8620     if (rc > 0) rc = 0;
8621
8622     /* if all went well, get the token from the acknowledgement packet */
8623     if ((bind_flags & TOKEN_REQUEST ) && ( rc >= 0)) {
8624         rc = bind_ack->TOKEN_value;
8625     }
8626
8627     /* free up the memory we allocated earlier */
8628     free(bind_req);
8629     free(bind_ack);
8630
8631 #ifdef TRACE
8632     printf( "TRACE: leaving x25bind\n" );
8633 #endif /* TRACE */
8634
8635     return( rc );
8636 }
8637
8638 /*****************************************************************************
8639 * Function: x25call
8640 * Description:  This routine builds and sends an N_CONN_REQ primitive, then
8641 *               checks for an N_CONN_CON primitive in return.
8642 *
8643 * Parameters:
8644 * fd    - file descriptor of stream
8645 * caddr - called address (remote address)
8646 *
8647 * Functions Referenced:
8648 * malloc()
8649 * bzero()
8650 * getmsg()
8651 * putmsg()
8652 *
8653 * Return code:
8654 * 0 - if successful
8655 * -1 if not successful
8656 *****************************************************************************/
8657 int
8658 x25call(fd, remote_nua, cud)
8659     int fd;                             /* X25 device (opened) */
8660     char * remote_nua;                  /* remote address to call */
8661     char * cud;                         /* call user data */
8662 /* x25call */ {
8663     int rc;                             /* return code */
8664     int flags;                          /* Connection flags */
8665     int get_flags;                      /* priority flags for getmsg */
8666     ulong type;                         /* primitive type */
8667     N_conn_req_t *connreq_ctl;          /* pointer to N_CONN_REQ primitive */
8668     N_npi_data_t *connreq_data;         /* pointer to N_CONN_REQ data (CUD) */
8669     int connreq_data_len;               /* length of filled data buffer */
8670     N_conn_con_t *conncon_ctl;          /* pointer to N_CONN_CON primitive */
8671     N_npi_data_t *conncon_data;         /* pointer to any data associated with
8672                                          * the N_CONN_CON primitive */
8673     char *addtl_info;                   /* pointer to additional info needed
8674                                          * for N_CONN_REQ primitive */
8675     int addr_len;                       /* length of address */
8676
8677 #ifdef TRACE
8678     printf( "TRACE: entering x25call\n" );
8679 #endif /* TRACE */
8680
8681 #ifdef DEBUG
8682     printf( "x25call( %d, %s )\n", fd, remote_nua );
8683     printf( "connecting to %s on fd %d\n", remote_nua, fd );
8684 #endif /* DEBUG */
8685
8686     /*
8687      * Allocate and zero out space for the N_CONN_REQ primitive
8688      * use the size of the generic NPI primitive control buffer
8689      */
8690     connreq_ctl  = (N_conn_req_t *) malloc(sizeof(N_npi_ctl_t));
8691     if (connreq_ctl == NULL){
8692         perror("kermit: x25call(): connreq_ctl malloc failed");
8693         return(-1);
8694     }
8695     bzero(connreq_ctl,sizeof(N_npi_ctl_t));
8696     /*
8697      * Build the Connection Request Primitive
8698      */
8699     flags = 0;
8700     connreq_ctl->PRIM_type = (ulong) N_CONN_REQ;
8701
8702     /* Note that the address length is nchai+1 and not n+2. The line number
8703      * is only passed with the address for the bind. The first byte of
8704      * the address for the N_CONN primitives contains the X.121
8705      * address prefix, which must be zero. The remaining bytes are the
8706      * address itself.
8707      */
8708     addr_len = strlen( remote_nua );
8709     connreq_ctl->DEST_length = (ulong) (addr_len + 1);
8710     connreq_ctl->DEST_offset = (ulong) sizeof(N_conn_req_t);
8711     /* connreq_ctl->CONN_flags = (ulong)EX_DATA_OPT | REC_CONF_OPT; */
8712     connreq_ctl->CONN_flags = (ulong) 0;
8713     connreq_ctl->QOS_length = (ulong) 0;        /* unsupported in AIX 4.1 */
8714     connreq_ctl->QOS_offset = (ulong) 0;        /* unsupported in AIX 4.1 */
8715
8716     addtl_info = (char *) ((void*)connreq_ctl + connreq_ctl->DEST_offset);
8717     *addtl_info++ = (char) 0; /* X.121 format */
8718     bcopy( remote_nua, addtl_info, addr_len );
8719
8720     /*
8721      * setup the data buffer for the connection request
8722      */
8723     connreq_data  = (N_npi_data_t *) malloc(sizeof(N_npi_data_t));
8724     if (connreq_data == NULL){
8725         perror("kermit: x25call(): connreq_data malloc failed");
8726         return(-1);
8727     }
8728     bzero(connreq_data,sizeof(N_npi_data_t));
8729
8730     /* facility selection needs to be put in the front of connreq_data */
8731     connreq_data_len = 0;
8732     connreq_data_len += x25facilities( (char *)connreq_data );
8733     if (cud && *cud) {
8734         bcopy(cud,
8735               (char *)((char *)connreq_data + connreq_data_len),
8736               strlen(cud)
8737               );
8738         connreq_data_len += strlen( cud );
8739         }
8740
8741     /*
8742      * Call putmsg() to put the connection request message on the stream
8743      */
8744     rc = x25putmsg( fd, (N_npi_ctl_t*)connreq_ctl, connreq_data,
8745             connreq_data_len, &flags );
8746     if (rc < 0) {
8747         return(-1);
8748     }
8749
8750     /*
8751      * Allocate and zero out space for the N_CONN_CON primitive
8752      */
8753     if ((conncon_ctl = (N_conn_con_t *) malloc(sizeof(N_npi_ctl_t))) == NULL) {
8754         perror("kermit: x25call(): conncon_ctl malloc failed");
8755         return(-1);
8756     }
8757     bzero(conncon_ctl, sizeof(N_npi_ctl_t));
8758
8759     /*
8760      * Allocate and zero out space for any data associated with N_CONN_CON
8761      */
8762     if ( (conncon_data = (N_npi_data_t *) malloc(NPI_MAX_DATA)) == NULL) {
8763         perror("kermit: x25call(): conncon_data malloc failed");
8764         return(-1);
8765     }
8766     bzero(conncon_data, NPI_MAX_DATA);
8767
8768     /* Initialize and build the structures for getmsg */
8769     get_flags=0;
8770
8771     rc = x25getmsg( fd, (N_npi_ctl_t*)conncon_ctl, (int)sizeof( N_conn_con_t ),
8772             conncon_data, NPI_MAX_DATA, &get_flags, N_CONN_CON );
8773
8774     /* turn quantitive return code into a qualitative one */
8775     if (rc > 0) rc = 0;
8776
8777     /* Free the space that we no longer need */
8778     if (connreq_ctl) { free(connreq_ctl); connreq_ctl = NULL; }
8779     if (conncon_ctl) { free(conncon_ctl); conncon_ctl = NULL; }
8780     if (conncon_data) { free(conncon_data); conncon_data = NULL; }
8781
8782 #ifdef TRACE
8783     printf( "TRACE: leaving x25call\n" );
8784 #endif /* TRACE */
8785
8786     return(rc);
8787 }
8788
8789 /*****************************************************************************
8790  * Function: x25getcall
8791  *
8792  * Description: This routine checks for an incomming call, verified
8793  * that it is a CONNIND (connection indication) message, and then
8794  * accepts the call and returns the file descriptor of the new stream
8795  *
8796  * Parameters:
8797  * fd   - file descriptor of listening stream
8798  *
8799  * Return Codes:
8800  * callfd       - file descriptor of connected incomming call.
8801  *              - set to -1 if an error occured
8802  *
8803  *****************************************************************************/
8804 int
8805 x25getcall(fd) int fd; {
8806     int x25callfd;                      /* fd of incomming call */
8807     N_conn_ind_t *connind_ctl;          /* connind controll buffer */
8808     N_npi_data_t *connind_data;         /* connind data buffer */
8809     int get_flags;                      /* flags for getmsg */
8810     ulong flags;                        /* connection flags */
8811     int rc;                             /* return code */
8812
8813     extern x25addr_t remote_nua;        /* remote X.25 addr global var */
8814
8815 #ifdef TRACE
8816     printf( "TRACE: entering x25getcall\n" );
8817 #endif /* TRACE */
8818
8819     /* allocate space for connection indication buffers */
8820     if ((connind_ctl = (N_conn_ind_t *)malloc(sizeof(N_npi_ctl_t))) == NULL) {
8821         perror("kermit: x25getcall(): connind_ctl malloc failed");
8822         return (-1);
8823     }
8824     bzero(connind_ctl, sizeof(N_npi_ctl_t));
8825
8826     if ((connind_data = (N_npi_data_t *)malloc(NPI_MAX_DATA)) == NULL) {
8827         perror("kermit: x25getcall(): connind_data malloc failed");
8828         return (-1);
8829     }
8830     bzero(connind_data, NPI_MAX_DATA);
8831
8832     /* initialise control structures */
8833     get_flags = 0;
8834
8835     /* call getmsg to check for a connection indication */
8836     if (x25getmsg(fd,
8837                   (N_npi_ctl_t*)connind_ctl,
8838                   (int)sizeof(N_conn_ind_t),
8839                   connind_data,
8840                   NPI_MAX_DATA,
8841                   &get_flags,
8842                   N_CONN_IND
8843                   ) < 0) {
8844 #ifdef DEBUG
8845         printf( "x25getcall(): errno is: %d\n", errno );
8846 #endif /* DEBUG */
8847         perror ("x25getcall(): getmsg failed");
8848         return(-1);
8849     }
8850
8851     /* a connection indication was received
8852      * - pull it to bits and answer the call
8853      */
8854     x25seqno = connind_ctl->SEQ_number;
8855     flags = connind_ctl->CONN_flags;
8856 #ifdef DEBUG
8857     printf( "setting remote_nua to a new value due to incomming call\n" );
8858 #endif /* DEBUG */
8859     /*
8860      * no guarantee that the address is null terminated, ensure that
8861      * after copying that it is (assumption: remote_nua is longer than
8862      * the address + 1)
8863      */
8864     bzero(remote_nua, sizeof(remote_nua));
8865     /* note: connind_ctl contains a x121 address, which has a null as
8866      * the FIRST character - strip it off!
8867      */
8868     ckstrncpy(remote_nua,
8869             (char*)((char*)connind_ctl + connind_ctl->SRC_offset + 1),
8870             connind_ctl->SRC_length - 1
8871             );
8872 #ifdef DEBUG
8873     printf( "remote_nua set to new value of %s\n", remote_nua );
8874 #endif /* DEBUG */
8875
8876     /* errors handled by callee */
8877     x25callfd = x25accept(x25seqno, flags);
8878
8879     /* free the malloc'd buffers */
8880     if (connind_ctl) { free(connind_ctl); connind_ctl = NULL; }
8881     if (connind_data) { free(connind_data); connind_data = NULL; }
8882
8883 #ifdef TRACE
8884     printf( "TRACE: leaving x25getcall\n" );
8885 #endif /* TRACE */
8886
8887     /* return the file descriptor (or error if < 0) */
8888     return( x25callfd );
8889 }
8890
8891 /*****************************************************************************
8892  * Function: x25accept
8893  *
8894  * Description: accept an incomming call
8895  *              This essentially means opening a new STREAM and sending
8896  *              an acknowledge back to the caller.
8897  *
8898  * Parameters:
8899  *      seqno   - sequence number for acknowledgement
8900  *      flags   - flags passed to us by the caller
8901  *
8902  * Return Codes:
8903  *      fd      - file descriptor of new STREAM
8904  *                set to -1 if an error occured
8905  *
8906  *****************************************************************************/
8907 int
8908 x25accept(seqno,flags)
8909     ulong seqno;                        /* connection sequence number */
8910     ulong flags;                        /* connection flags */
8911 /* x25accept */ {
8912     int x25callfd;                      /* fd for incomming call */
8913     int get_flags;                      /* priority flags for getmsg */
8914     int put_flags = 0;                  /* flags for putmsg, always 0 */
8915     int addr_len;                       /* length of local address */
8916     ulong token;                        /* connection token */
8917     N_conn_res_t *conn_res;             /* N_CONN_RES primitive */
8918     N_ok_ack_t *ok_ack;                 /* N_OK_ACK primitive */
8919     char *addtl_info;                   /* temp pointer */
8920     int rc;                             /* temporary return code */
8921
8922 /* global variables from ckcmai.c */
8923     extern int revcall, closgr, cudata;
8924     extern char udata[];
8925     extern x25addr_t local_nua;         /* local X.25 address */
8926     extern char x25name[];              /* x25 device name (sx25a0) */
8927     extern char x25dev[];               /* x25 device file /dev/x25pkt */
8928     extern int x25port;                 /* logical port to use */
8929     ulong bind_flags = 0;               /* flags for binding the X25 stream */
8930
8931 #ifdef TRACE
8932     printf( "TRACE: entering x25accept\n" );
8933 #endif /* TRACE */
8934
8935     /* open a new packet level stream */
8936     if ((x25callfd = open(x25dev, O_RDWR)) < 0) {
8937         perror ("kermit: x25accept(): X.25 device open error");
8938         debug(F101,"x25accept() device open error","",errno);
8939         return(-1);
8940     }
8941
8942     /* push the NPI onto the STREAM */
8943     if (ioctl(x25callfd,I_PUSH,"npi") < 0) {
8944         perror( "kermit: x25accept(): couldn't push npi on the X25 stream" );
8945         debug(F101,"x25accept can't push npi on the X25 stream","",errno);
8946         return (-1);
8947     }
8948
8949     /* bind kermit server to the local X25 address */
8950     /* taken from /usr/samples/sx25/npi/npiserver.c (AIX 4) */
8951     bind_flags |= TOKEN_REQUEST;
8952     token = x25bind(x25callfd,local_nua,(char *)NULL,0,0,x25port,bind_flags);
8953     if (token < 0) {
8954         printf( "kermit: x25accept(): couldn't bind to local X25 address\n" );
8955         netclos();
8956         return(-1);
8957     }
8958
8959     /* allocate connection response primitive */
8960     if ((conn_res = (N_conn_res_t *)malloc( NPI_MAX_CTL )) == NULL) {
8961         perror("kermit: x25accept(): conn_res malloc failed");
8962         return (-1);
8963     }
8964     bzero((char *)conn_res, NPI_MAX_CTL);
8965
8966     /* setup connection response primitive */
8967     addr_len = strlen( local_nua );
8968     conn_res->PRIM_type = (ulong)N_CONN_RES;
8969     conn_res->TOKEN_value = token;
8970     /* note address length is n+1 to accomodate the X.121 address prefix */
8971     conn_res->RES_length = (ulong)(addr_len + 1);
8972     conn_res->RES_offset = (ulong)sizeof( N_conn_res_t );
8973     conn_res->SEQ_number = seqno;
8974     conn_res->CONN_flags = 0;
8975     conn_res->QOS_length = 0;           /* unsupported - must be 0 (!?) */
8976     conn_res->QOS_offset = 0;
8977
8978     addtl_info = (char *)((char *)conn_res + conn_res->RES_offset);
8979     *addtl_info++ = (char)0;    /* X.121 address prefix */
8980     bcopy( local_nua, addtl_info, addr_len );
8981
8982     /*
8983      * send off the connect response
8984      */
8985     if (x25putmsg(x25callfd,
8986                   (N_npi_ctl_t*)conn_res,
8987                   (N_npi_data_t *)NULL,
8988                   0,
8989                   &put_flags
8990                   ) < 0 ) {
8991         perror("kermit: x25accept(): putmsg connect response failed");
8992         return(-1);
8993     }
8994
8995     /*
8996      * Allocate and zero out space for the OK_ACK primitive
8997      */
8998     if ((ok_ack = (N_ok_ack_t *) malloc(sizeof(N_npi_ctl_t))) == NULL) {
8999         perror("kermit: x25call(): ok_ack malloc failed");
9000         return(-1);
9001     }
9002     bzero(ok_ack, sizeof(N_npi_ctl_t));
9003
9004     /* Initialize and build the structures for getmsg */
9005     get_flags=0;
9006
9007     rc = (int)x25getmsg(x25callfd,
9008                         (N_npi_ctl_t*)ok_ack,
9009                         (int)sizeof(N_ok_ack_t),
9010                         (N_npi_data_t*)NULL,
9011                         0,
9012                         &get_flags,
9013                         N_OK_ACK
9014                         );
9015     if (rc == 0) {
9016         /* sequence number is only for disconnecting when not connected !? */
9017         x25seqno = 0;
9018     }
9019
9020     /* free up malloc'ed buffer space */
9021     if (conn_res) { free(conn_res); conn_res = NULL; }
9022     if (ok_ack) { free(ok_ack); ok_ack = NULL; }
9023
9024 #ifdef TRACE
9025     printf( "TRACE: leaving x25accept\n" );
9026 #endif /* TRACE */
9027
9028     return( ( rc >= 0 ) ? x25callfd : -1 );
9029 }
9030
9031 /*****************************************************************************
9032  * Function: x25unbind
9033  *
9034  * Description:  This subroutine builds and sends an unbind request and gets
9035  * the acknowledgement for it.
9036  *
9037  * Parameters:
9038  * fd - File descriptor of the stream
9039  *
9040  * Functions Referenced:
9041  * getmsg()
9042  * putmsg()
9043  * malloc()
9044  * bzero()
9045  *
9046  * Return code:
9047  * 0 - if successful
9048  * -1 - if not successful
9049  *****************************************************************************/
9050 int
9051 x25unbind(fd) int fd; {                 /* X25 device (opened) */
9052     int rc;                             /* return code */
9053     int flags;                          /* bind flags */
9054     int get_flags;                      /* priority flag for getmsg */
9055     ulong type;                         /* primitive type */
9056     N_unbind_req_t *unbind_req;         /* pointer to N_UNBIND_REQ */
9057     N_ok_ack_t *ok_ack;                 /* pointer to N_OK_ACK */
9058
9059 #ifdef TRACE
9060     printf( "TRACE: entering x25unbind\n" );
9061 #endif /* TRACE */
9062
9063 #ifdef DEBUG
9064     /* printf( "x25unbind( %d )\n", fd ); */
9065 #endif /* DEBUG */
9066     debug(F101,"x25unbind closing x25 connection #","",fd);
9067
9068     /* Allocate and zero out space to hold the N_UNBIND_REQ primitive */
9069     unbind_req = (N_unbind_req_t *) malloc(sizeof(N_npi_ctl_t));
9070     if (unbind_req == NULL) {
9071         perror("kermit: x25unbind(): unbind_req malloc failed");
9072         return(-1);
9073     }
9074     bzero(unbind_req, sizeof(N_npi_ctl_t));
9075
9076     /*
9077      * Build the Unbind Request Primitive
9078      */
9079     flags = 0;
9080     unbind_req->PRIM_type = (ulong) N_UNBIND_REQ;
9081
9082     /*
9083      * Call putmsg() to put the bind request message on the stream
9084      */
9085     if (x25putmsg(fd,
9086                   (N_npi_ctl_t*)unbind_req,
9087                   (N_npi_data_t *)NULL,
9088                   0,
9089                   &flags
9090                   ) < 0) {
9091         perror ("kermit: x25unbind(): putmsg failed");
9092         return(-1);
9093     }
9094
9095     /* Allocate and Zero out space for the N_OK_ACK primitive */
9096     ok_ack = (N_ok_ack_t *) malloc(sizeof(N_npi_ctl_t));
9097     if (ok_ack == NULL) {
9098         perror("kermit x25unbind(): ok_ack malloc failed\n");
9099         return(-1);
9100     }
9101     bzero(ok_ack, sizeof(N_npi_ctl_t));
9102
9103     /* Initialize and build the control structure for getmsg */
9104     get_flags=0;
9105
9106     /* Call getmsg() to check for an acknowledgement */
9107     rc = x25getmsg(fd,
9108                    (N_npi_ctl_t*)ok_ack,
9109                    (int)sizeof(N_ok_ack_t),
9110                    (N_npi_data_t*)NULL,
9111                    0,
9112                    &get_flags,
9113                    N_OK_ACK
9114                    );
9115     if (rc < 0) {
9116         perror ("kermit: x25unbind: getmsg failed");
9117         return(-1);
9118     }
9119
9120     /* Free up the space that we no longer need */
9121     if (unbind_req) { free(unbind_req); unbind_req = NULL; }
9122     if (ok_ack) { free(ok_ack); ok_ack = NULL; }
9123
9124 #ifdef TRACE
9125     printf( "TRACE: leaving x25unbind\n" );
9126 #endif /* TRACE */
9127
9128     return(0);
9129 }
9130
9131 /*****************************************************************************
9132  * Function: x25xin
9133  *
9134  * Description:
9135  *      Read n characters from X.25 circuit into buf (AIX only)
9136  *
9137  * Parameters:
9138  *      data_buf_len    maximum size of data buffer
9139  *      data_buf        pointer to pre-allocated buffer space
9140  *
9141  * Return Value:
9142  *      the number of characters actually read
9143  */
9144 int
9145 x25xin(data_buf_len,data_buf) int data_buf_len; CHAR *data_buf; {
9146     struct strbuf getmsg_ctl;           /* streams control structure */
9147     struct strbuf getmsg_data;          /* streams data structure */
9148     int rc = 0;                         /* return code */
9149     int getmsg_flags;                   /* packet priority flags */
9150     char * ctl_buf;                     /* npi control buffer */
9151     N_npi_ctl_t * result;               /* pointer to simplify switch() */
9152
9153 #ifdef TRACE
9154     printf( "TRACE: entering x25xin\n" );
9155 #endif /* TRACE */
9156
9157     /* ensure that no maximum's are overridden */
9158     data_buf_len = (NPI_MAX_DATA < data_buf_len) ? NPI_MAX_DATA : data_buf_len;
9159
9160     /* allocate space for packet control info */
9161     if ((ctl_buf = (char *)malloc(NPI_MAX_CTL)) == NULL) {
9162         perror( "kermit: x25xin(): ctl_buf malloc" );
9163         return(-1);
9164     }
9165 #ifdef COMMENT
9166     /* riehm: need zeroed buffer for getmsg? */
9167     bzero( ctl_buf, NPI_MAX_CTL );
9168     /* clear data buffer */
9169     bzero( data_buf, data_buf_len );
9170 #endif /* COMMENT */
9171
9172     getmsg_flags = 0;                   /* get the first packet available */
9173
9174     rc = x25getmsg(ttyfd,
9175                    ctl_buf,
9176                    NPI_MAX_CTL,
9177                    data_buf,
9178                    data_buf_len,
9179                    &getmsg_flags,
9180                    N_DATA_IND
9181                    );
9182 #ifdef COMMENT
9183 #ifdef DEBUG
9184     if (rc >= 0) {
9185         printf( "kermit: x25xin(): got " );
9186         x25dump_data( data_buf, 0, rc );
9187     } else {
9188         printf( "x25xin(): attempt to get data resulted in an error\n" );
9189     }
9190 #endif /* DEBUG */
9191 #endif /* COMMENT */
9192
9193     /* free buffers */
9194     if (ctl_buf) { free(ctl_buf); ctl_buf = NULL; }
9195
9196 #ifdef TRACE
9197     printf( "TRACE: leaving x25xi\n" );
9198 #endif /* TRACE */
9199
9200     return(rc);
9201 }
9202
9203 /*****************************************************************************
9204  * Function: x25write
9205  *
9206  * Description:
9207  *      write a block of characters to the X25 STREAM (AIX)
9208  *
9209  * Parameters:
9210  *      fd              file descriptor to write to
9211  *      databuf         buffer containing data to write
9212  *      databufsize             size of the buffer to write
9213  *
9214  * Return Value:
9215  *      size            the number of bytes actually transmitted
9216  */
9217 int
9218 x25write(fd, databuf, databufsize)
9219     int         fd;                  /* X25 STREAMS file descriptor (ttyfd) */
9220     char        *databuf;               /* buffer to write */
9221     int         databufsize;            /* buffer size */
9222 /* x25write */ {
9223     N_data_req_t *data_req_ctl;
9224     int rc;                             /* return code (size transmitted) */
9225     int write_flags = 0;                /* always 0 !? */
9226
9227 #ifdef TRACE
9228     printf( "TRACE: entering x25write\n" );
9229 #endif /* TRACE */
9230
9231     if ((data_req_ctl = (N_data_req_t *)malloc(NPI_MAX_CTL) ) == NULL) {
9232         perror( "kermit: x25write(): data_req_ctl malloc" );
9233         return(-1);
9234     }
9235     data_req_ctl->PRIM_type = N_DATA_REQ;
9236     data_req_ctl->DATA_xfer_flags = 0;
9237
9238     /* riehm: possible extension
9239      * possibly need to think about splitting up the data buffer
9240      * into multiple parts if databufsize > NPI_MAX_DATA
9241      */
9242
9243 #ifdef COMMENT
9244 #ifdef DEBUG
9245     printf( "kermit: x25write(): writing data to x25 stream\n" );
9246     printf( "\tdata:\t" );
9247     x25dump_data(databuf, 0, databufsize);
9248 #endif /* DEBUG */
9249 #endif /* COMMENT */
9250     rc = x25putmsg(fd,
9251                    (N_npi_ctl_t*)data_req_ctl,
9252                    (N_npi_data_t*)databuf,
9253                    databufsize,
9254                    &write_flags
9255                    );
9256     if (data_req) { free(data_req_ctl);  data_req = NULL; }
9257
9258 #ifdef TRACE
9259     printf( "TRACE: leaving x25write\n" );
9260 #endif /* TRACE */
9261
9262     return(rc);
9263 }
9264
9265 /*****************************************************************************
9266  * Function: x25local_nua
9267  *
9268  * Description:
9269  *      This routine is only interesting for IBM computers. In order
9270  *      to set up a connection (see x25bind()) you need to know the
9271  *      local NUA (x25 address). Unfortunately, you need all this code
9272  *      to find that out, I just hope this works for everyone else!
9273  *
9274  * Parameters:
9275  *      a pre-allocated character buffer, long enough to hold an X.25 address
9276  *      and the tailing null.
9277  *
9278  * Return Value:
9279  *      the length of the address string.
9280  *      0 = error
9281  */
9282 int
9283 x25local_nua(char *buf) {
9284     struct CuAt *response;      /* structure to fill with info from ODM */
9285     CLASS_SYMBOL retClass;      /* ODM class */
9286     char query[64];             /* odm database query */
9287     int rc = 0;                 /* return value (length of local NUA) */
9288     extern char x25name[];      /* x25 device name (sx25a0) */
9289
9290 #ifdef TRACE
9291     printf( "TRACE: entering x25local_nua\n" );
9292 #endif /* TRACE */
9293
9294     /* set up query string */
9295     if (x25name[0] == '\0') {
9296 #ifdef DEBUG
9297         printf( "kermit: x25local_nua(): No x25 device set, trying sx25a0\n" );
9298 #endif /* DEBUG */
9299         strcpy( x25name, "sx25a0" );
9300     }
9301     ckmakmsg(query, sizeof(query), "name like ",x25name,
9302              " and attribute like local_nua");
9303
9304     /* initialise ODM database */
9305     odmerrno = 0;
9306     if (odm_initialize() == -1) {
9307         printf( "x25local_nua(): can't initialize ODM database");
9308         switch (odmerrno) {
9309           case ODMI_INVALID_PATH:
9310             printf( "invalid path\n" );
9311             break;
9312           case ODMI_MALLOC_ERR:
9313             printf( "malloc failed\n" );
9314             break;
9315           default:
9316             printf( "unknown error %d\nPlease call IBM\n", odmerrno );
9317         }
9318         return(rc);
9319     }
9320
9321     /* open the CuAt class */
9322     retClass = odm_open_class(CuAt_CLASS);
9323     if (((int)retClass) == -1) {
9324         printf( "kermit: x25local_nua(): can't open CuAt class in odm. " );
9325         switch (odmerrno) {
9326           case ODMI_CLASS_DNE:
9327             printf( "CuAt class doesn't exist\n" );
9328             break;
9329           case ODMI_CLASS_PERMS:
9330             printf( "permission to CuAt class file denied\n" );
9331             break;
9332           case ODMI_MAGICNO_ERR:
9333             printf( "CuAt is an invalid ODM object class\n" );
9334             break;
9335           case ODMI_OPEN_ERR:
9336             printf( "cannot open CuAt class - and don't know why!\n" );
9337             break;
9338           case ODMI_INVALID_PATH:
9339             printf( "invalid path\n" );
9340             break;
9341           case ODMI_TOOMANYCLASSES:
9342             printf( "too many object classes have been opened\n" );
9343             break;
9344           default:
9345             printf( "unknown error %d\nPlease call IBM\n", odmerrno );
9346         }
9347         return(rc);
9348     }
9349
9350 #ifdef DEBUG
9351     printf("retClass= %d\n", retClass);
9352 #endif /* DEBUG */
9353
9354     response = (struct CuAt *)odm_get_first( retClass, query, NULL );
9355     if (((int)response) == -1) {
9356         printf( "kermit: x25local_nua(): odm query failed " );
9357         switch (odmerrno) {
9358           case ODMI_BAD_CRIT:           /* Programming error */
9359             printf( "bad search criteria\n" );
9360             break;
9361           case ODMI_CLASS_DNE:
9362             printf( "CuAt class doesn't exist\n" );
9363             break;
9364           case ODMI_CLASS_PERMS:
9365             printf( "permission to CuAt class file denied\n" );
9366             break;
9367           case ODMI_INTERNAL_ERR:
9368             printf("odm internal error\nPlease contact your administrator\n" );
9369             break;
9370           case ODMI_INVALID_CLXN:
9371             printf("CuAt is invalid or inconsistent odm class collection\n");
9372             break;
9373           case ODMI_INVALID_PATH:
9374             printf( "invalid path\n" );
9375             break;
9376           case ODMI_MAGICNO_ERR:
9377             printf( "CuAt is an invalid ODM object class\n" );
9378             break;
9379           case ODMI_MALLOC_ERR:
9380             printf( "malloc failed\n" );
9381             break;
9382           case ODMI_OPEN_ERR:
9383             printf( "cannot open CuAt class - and don't know why!\n" );
9384             break;
9385           case ODMI_TOOMANYCLASSES:
9386             printf( "too many object classes have been opened\n" );
9387             break;
9388           default:
9389             printf( "unknown error %d\nPlease call IBM\n", odmerrno );
9390         }
9391         return(rc);
9392     }
9393
9394     /* check for a meaningfull response */
9395     if (response != NULL) {
9396         if (response->value != NULL) {
9397             strcpy(buf, response->value);
9398             rc = strlen( buf );
9399 #ifdef DEBUG
9400 /*
9401             printf( "attribute name is: %s\n", (char *)response->attribute );
9402             printf( "I think my address is %s\n", (char*)response->value );
9403 */
9404 #endif /* DEBUG */
9405         } else {
9406             printf( "kermit: x25local_nua(): couldn't find the local NUA\n" );
9407         }
9408     } else {
9409         switch (odmerrno) {
9410           case ODMI_BAD_CRIT:
9411             printf( "Error: ODMI_BAD_CRIT - bad criteria\n" );
9412             break;
9413           case ODMI_CLASS_DNE:
9414             printf( "Error: ODMI_CLASS_DNE - class doesn't exist\n" );
9415             break;
9416           case ODMI_CLASS_PERMS:
9417             printf( "Error: ODMI_CLASS_PERMS - class permissions\n" );
9418             break;
9419           case ODMI_INTERNAL_ERR:
9420             printf( "Error: ODMI_INTERNAL_ERR - panic\n" );
9421             break;
9422           case ODMI_INVALID_CLXN:
9423             printf( "Error: ODMI_INVALID_CLXN - invalid collection\n" );
9424             break;
9425           case ODMI_INVALID_PATH:
9426             printf( "Error: ODMI_INVALID_PATH - invalid path - what path?\n" );
9427             break;
9428           case ODMI_MAGICNO_ERR:
9429             printf( "Error: ODMI_MAGICNO_ERR - invalid object magic\n" );
9430             break;
9431           case ODMI_MALLOC_ERR:
9432             printf( "Error: ODMI_MALLOC_ERR - malloc failed\n" );
9433             break;
9434           case ODMI_OPEN_ERR:
9435             printf( "Error: ODMI_OPEN_ERR - cannot open class\n" );
9436             break;
9437           case ODMI_TOOMANYCLASSES:
9438             printf( "Error: ODMI_TOOMANYCLASSES - too many classes\n" );
9439             break;
9440           default:
9441             printf( "Unknown error!\n" );
9442         }
9443         return(rc);
9444     }
9445
9446     /* close the database again */
9447     odm_close_class( retClass );
9448
9449     /* forget about ODM all together */
9450     odm_terminate();
9451
9452 #ifdef TRACE
9453     printf( "TRACE: leaving x25local_nua\n" );
9454 #endif /* TRACE */
9455
9456     debug(F110, "x25local_nua local address is ", buf, 0);
9457     return(rc);
9458 }
9459
9460 /*****************************************************************************
9461  * Function: x25facilities
9462  *
9463  * Description:
9464  *      build up the facilities data packet for a connection request
9465  *
9466  * Parameters:
9467  *      a pre-allocated char buffer, normally NPI_MAX_DATA big.
9468  *
9469  * Return Value:
9470  *      the number of characters inserted into the buffer
9471  */
9472 int
9473 x25facilities(buffer) char *buffer; {
9474     extern int revcall;
9475     extern int closgr;
9476     char *p;                            /* temp pointer */
9477     char *start;                        /* temp pointer */
9478
9479 #ifdef TRACE
9480     printf( "TRACE: entering x25facilities\n" );
9481 #endif /* TRACE */
9482
9483     p = buffer + 1;
9484     start = p;
9485
9486 #ifdef DEBUG
9487     printf( "kermit: x25facilities(): getting X25 facilities\n" );
9488 #endif /* DEBUG */
9489
9490     if (revcall != 0) {
9491 #ifdef DEBUG
9492         printf("reverse charge: %d\n", revcall );
9493 #endif /* DEBUG */
9494         *++p = 0x01;
9495         *++p = revcall;
9496     }
9497     if (closgr > 0) {
9498 #ifdef DEBUG
9499         printf("closed user group: %d\n", closgr );
9500 #endif /* DEBUG */
9501         *++p = 0x03;
9502         *++p = closgr;
9503     }
9504
9505 #ifdef DEBUG
9506     if (p == start) {
9507         printf( "no facilities\n" );
9508     }
9509 #endif /* DEBUG */
9510
9511     /* set the size of the facilities buffer */
9512     *buffer = (char)( p - start ) & 0xff;
9513
9514 #ifdef DEBUG
9515     printf( "kermit: x25facilities(): returning %d\n", (int)(p - buffer)  );
9516 #endif /* DEBUG */
9517
9518 #ifdef TRACE
9519     printf( "TRACE: leaving x25facilities\n" );
9520 #endif /* TRACE */
9521
9522     /* return the size of the facilities with size byte */
9523     /* 1 == no facilities, 0 byte returned as facilities size */
9524     return( (int)(p - buffer) );
9525 }
9526
9527 /*
9528  * reset the connection
9529  */
9530 int
9531 x25reset(cause, diagn) char cause; char diagn; {
9532     /* not implemented */
9533
9534 #ifdef TRACE
9535     printf( "TRACE: entering x25reset\n" );
9536 #endif /* TRACE */
9537
9538 #ifdef TRACE
9539     printf( "TRACE: leaving x25reset\n" );
9540 #endif /* TRACE */
9541
9542     return(0);
9543 }
9544
9545 /*
9546  * clear the x25 connection - ie: hang up
9547  */
9548 int
9549 x25clear() {
9550     int get_flags = 0;                  /* priority flag for getmsg */
9551     int put_flags = 0;                  /* send flags, always 0 */
9552     ulong type;                         /* primitive type */
9553     N_discon_req_t *discon_req;         /* pointer to N_DISCON_REQ */
9554     N_discon_ind_t *discon_ind;         /* pointer to N_DISCON_IND */
9555     N_npi_data_t *discon_data;          /* pointer to N_DISCON_IND data */
9556     int rc = 0;                         /* return code */
9557
9558 #ifdef TRACE
9559     printf( "TRACE: entering x25clear\n" );
9560 #endif /* TRACE */
9561
9562 #ifdef DEBUG
9563     /* printf( "x25clear(): checking last msg: %s\n", x25prim(x25lastmsg)); */
9564 #endif /* DEBUG */
9565
9566     /*
9567     * The following checks are used to ensure that we don't disconnect
9568     * or unbind twice - this seems to throw the NPI interface right out of
9569     * kilter.
9570     */
9571     switch(x25lastmsg) {
9572       case N_BIND_ACK:
9573       case N_CONN_CON:
9574       case N_CONN_REQ:
9575       case N_DATA_REQ:
9576       case N_DATA_IND:
9577         {
9578 #ifdef DEBUG
9579             /* printf("x25clear(): actively disconnecting\n"); */
9580 #endif /* DEBUG */
9581
9582                 discon_req = (N_discon_req_t *)malloc(NPI_MAX_CTL);
9583                 if (discon_req == NULL) {
9584                     perror("kermit x25clear(): discon_req malloc failed\n");
9585                     /* fallthrough, try to unbind the NPI anyway */
9586                 } else {
9587                     discon_req->PRIM_type = N_DISCON_REQ;
9588                     discon_req->DISCON_reason = 0;      /* not used by AIX */
9589                     discon_req->RES_length = 0;
9590                     discon_req->RES_offset = (ulong)(sizeof(N_discon_req_t));
9591                     discon_req->SEQ_number = x25seqno;  /* global */
9592
9593                     if (x25putmsg(ttyfd,
9594                                   (N_npi_ctl_t*)discon_req,
9595                                   (N_npi_data_t*)NULL,
9596                                   0,
9597                                   &put_flags
9598                                   ) < 0) {
9599                         perror("x25putmsg failed in x25clear()");
9600                     }
9601                     discon_ind = (N_discon_ind_t *)malloc(NPI_MAX_CTL);
9602                     discon_data = (N_npi_data_t *)malloc(NPI_MAX_DATA);
9603                     if((discon_ind == NULL) || (discon_data == NULL)) {
9604                         perror("x25clear(): discon_ind malloc failed\n");
9605                         /* fallthrough, try to unbind the NPI anyway */
9606                     } else {
9607                         if(x25getmsg(ttyfd,
9608                                      (N_npi_ctl_t*)discon_ind,
9609                                      NPI_MAX_CTL,
9610                                      (N_npi_data_t*)discon_data,
9611                                      NPI_MAX_DATA,
9612                                      &get_flags,
9613                                      N_OK_ACK
9614                                      ) < 0 ) {
9615                             perror("x25getmsg failed in x25clear()");
9616                             /* fallthrough, try to unbind the NPI anyway */
9617                         }
9618                     }
9619                 }
9620                 break;
9621             }
9622     }
9623
9624     if (x25lastmsg != N_UNBIND_REQ) {
9625         rc = x25unbind(ttyfd);
9626     }
9627
9628 #ifdef TRACE
9629     printf( "TRACE: leaving x25clear\n" );
9630 #endif /* TRACE */
9631
9632     return(rc);
9633 }
9634
9635 #ifdef DEBUG
9636 /*
9637  * only for debugging
9638  *
9639  * turn the internal representation of a datablock into something
9640  * half-way readable. Because the length is known, we can print
9641  * the string including null's etc (important, because the first(!)
9642  * byte of an X121 address is a null! (X121 addr == 0 + X25 addr)
9643  */
9644 x25dump_data(char *addr, ulong offset, ulong length) {
9645     char *ptr = addr + offset;
9646     ulong i = length;
9647     /* allocate enough memory for all unprintable chars */
9648     char *buf = (char *)malloc( length * 4 );
9649     char *bptr = buf;   /* pointer to current place in the print buffer */
9650
9651     while (i > 0) {
9652         if (isprint(*ptr)) {
9653             *bptr++ = *ptr;
9654         } else {
9655             *bptr++ = '[';
9656             strcpy(bptr,ckctox(*ptr,1)); bptr += 2;
9657             *bptr++ = ']';
9658         }
9659         ptr++;
9660         i--;
9661     }
9662     if (length > 0) {
9663         *bptr = '\0';
9664         printf( "%s", buf );
9665     }
9666     printf( " (%d+%d)\n", offset, length );
9667
9668     if (buf) { free(buf); buf = NULL; }
9669     return;
9670 }
9671
9672 /*
9673  * only for debugging
9674  * print as much useful information about a packet as possible
9675  */
9676 x25dump_prim(primitive)    N_npi_ctl_t *primitive; {
9677     printf("Primitive");
9678     switch (primitive->PRIM_type) {
9679       case N_BIND_ACK:
9680         printf( "\tN_BIND_ACK\n\taddress:\t" );
9681         x25dump_data( (char *)primitive,
9682                      primitive->bind_ack.ADDR_offset,
9683                      primitive->bind_ack.ADDR_length );
9684         printf( "\tproto id:\t" );
9685         x25dump_data( (char *)primitive,
9686                      primitive->bind_ack.PROTOID_offset,
9687                      primitive->bind_ack.PROTOID_length );
9688         printf( "\tconnind:\t%d\n\ttoken:\t\t%d\n",
9689                primitive->bind_ack.CONIND_number,
9690                primitive->bind_ack.TOKEN_value );
9691         break;
9692
9693       case N_BIND_REQ:
9694         printf( "\tN_BIND_REQ\n\taddress:\t" );
9695         x25dump_data( (char *)primitive,
9696                      primitive->bind_req.ADDR_offset,
9697                      primitive->bind_req.ADDR_length );
9698         printf( "\tproto id:\t" );
9699         x25dump_data( (char *)primitive,
9700                      primitive->bind_req.PROTOID_offset,
9701                      primitive->bind_req.PROTOID_length );
9702         printf( "\tconnind:\t%d\n\tflags:\t\t%d\n",
9703                primitive->bind_req.CONIND_number,
9704                primitive->bind_req.BIND_flags );
9705         break;
9706
9707       case N_CONN_CON:
9708         printf( "\tN_CONN_CON\n" );
9709         printf( "\tRES\t\t" );
9710         x25dump_data( (char *)primitive,
9711                      primitive->conn_con.RES_offset,
9712                      primitive->conn_con.RES_length );
9713         printf( "\tflags:\t%d\n", primitive->conn_con.CONN_flags );
9714         break;
9715
9716       case N_CONN_IND:
9717         printf( "\tN_CONN_IND\n" );
9718         printf( "\tsource:\t\t" );
9719         x25dump_data( (char *)primitive,
9720                      primitive->conn_ind.SRC_offset,
9721                      primitive->conn_ind.SRC_length );
9722         printf( "\tdestination:\t" );
9723         x25dump_data( (char *)primitive,
9724                      primitive->conn_ind.DEST_offset,
9725                      primitive->conn_ind.DEST_length );
9726         printf( "\tSEQ_number:\t%d\n", primitive->conn_ind.SEQ_number );
9727         printf( "\tflags:\t%d\n", primitive->conn_ind.CONN_flags );
9728         break;
9729
9730       case N_CONN_REQ:
9731         printf( "\tN_CONN_REQ\n\tdestination:\t" );
9732         x25dump_data( (char *)primitive,
9733                      primitive->conn_req.DEST_offset,
9734                      primitive->conn_req.DEST_length );
9735         printf( "\tflags:\t%d\n", primitive->conn_req.CONN_flags );
9736         break;
9737
9738       case N_CONN_RES:
9739         printf( "\tN_CONN_RES\n" );
9740         printf( "\tTOKEN_value\t%d\n", primitive->conn_res.TOKEN_value );
9741         printf( "\tSEQ_number\t%d\n", primitive->conn_res.SEQ_number );
9742         printf( "\tCONN_flags\t%d\n", primitive->conn_res.CONN_flags );
9743         printf( "\tRES\t\t" );
9744         x25dump_data( (char *)primitive,
9745                      primitive->conn_res.RES_offset,
9746                      primitive->conn_res.RES_length );
9747         break;
9748
9749       case N_DATACK_IND:
9750         printf( "\tN_DATACK_IND\n" );
9751         break;
9752
9753       case N_DATACK_REQ:
9754         printf( "\tN_DATACK_REQ\n" );
9755         printf( "\tflags:\t%d\n", primitive->data_req.DATA_xfer_flags );
9756         break;
9757
9758       case N_DATA_IND:
9759         printf( "\tN_DATA_IND\n" );
9760         printf( "\tflags:\t%d\n", primitive->data_ind.DATA_xfer_flags );
9761         break;
9762
9763       case N_DATA_REQ:
9764         printf( "\tN_DATA_REQ\n" );
9765         break;
9766
9767       case N_DISCON_IND:
9768         printf( "\tN_DISCON_IND\n" );
9769         printf( "\torigin:\t%d\n", primitive->discon_ind.DISCON_orig );
9770         printf( "\treason:\t\t%d\n", primitive->discon_ind.DISCON_reason );
9771         printf( "\tseq no:\t\t%d\n", primitive->discon_ind.SEQ_number );
9772         printf( "\tRES:\t" );
9773         x25dump_data( (char *)primitive,
9774                      primitive->discon_ind.RES_offset,
9775                      primitive->discon_ind.RES_length );
9776         break;
9777
9778       case N_DISCON_REQ:
9779         printf( "\tN_DISCON_REQ\n" );
9780         printf( "\tDISCON_reason:\t%d\n",
9781                primitive->discon_req.DISCON_reason );
9782         printf( "\tRES:\t" );
9783         x25dump_data( (char *)primitive,
9784                      primitive->discon_req.RES_offset,
9785                      primitive->discon_req.RES_length );
9786         printf( "\tSEQ_number:\t%d\n", primitive->discon_req.SEQ_number );
9787         break;
9788
9789       case N_ERROR_ACK:
9790         printf( "\tN_ERROR_ACK\n" );
9791         printf( "\tCaused by:\t%s\n",
9792                x25prim( primitive->error_ack.ERROR_prim ) );
9793         printf( "\tNPI error:\t%s\n",
9794                x25err( primitive->error_ack.NPI_error ));
9795         errno = primitive->error_ack.UNIX_error;
9796         perror( "\t" );
9797         break;
9798
9799       case N_EXDATA_IND:
9800         printf( "\tN_EXDATA_ACK\n" );
9801         break;
9802
9803       case N_EXDATA_REQ:
9804         printf( "\tN_EXDATA_REQ\n" );
9805         break;
9806
9807       case N_INFO_ACK:
9808         printf( "\tN_INFO_ACK\n" );
9809         printf( "\tNSDU size:\t%d\n", primitive->info_ack.NSDU_size );
9810         printf( "\tENSDU size:\t%d\n", primitive->info_ack.ENSDU_size );
9811         printf( "\tCDATA size:\t%d\n", primitive->info_ack.CDATA_size );
9812         printf( "\tDDATA size:\t%d\n", primitive->info_ack.DDATA_size );
9813         printf( "\tADDR size:\t%d\n", primitive->info_ack.ADDR_size );
9814         printf( "\tNIDU size:\t%d\n", primitive->info_ack.NIDU_size );
9815         break;
9816
9817       case N_INFO_REQ:
9818         printf( "\tN_INFO_REQ\n" );
9819         break;
9820
9821       case N_OK_ACK:
9822         printf( "\tN_OK_ACK\n" );
9823         break;
9824
9825       case N_OPTMGMT_REQ:
9826         printf( "\tN_OPTMGMT_REQ\n" );
9827         break;
9828
9829       case N_RESET_CON:
9830         printf( "\tN_RESET_CON\n" );
9831         break;
9832
9833       case N_RESET_IND:
9834         printf( "\tN_RESET_IND\n" );
9835         printf( "\treason:\t\t%d\n", primitive->reset_ind.RESET_reason );
9836         printf( "\torigin:\t\t%d\n", primitive->reset_ind.RESET_orig );
9837         break;
9838
9839       case N_RESET_REQ:
9840         printf( "\tN_RESET_REQ\n" );
9841         printf( "\treason:\t\t%d\n", primitive->reset_req.RESET_reason );
9842         break;
9843
9844       case N_RESET_RES:
9845         printf( "\tN_RESET_RES\n" );
9846         break;
9847
9848       case N_UDERROR_IND:
9849         printf( "\tN_UDERROR_IND\n" );
9850         break;
9851
9852       case N_UNBIND_REQ:
9853         printf( "\tN_UNBIND_REQ\n" );
9854         break;
9855
9856       case N_UNITDATA_REQ:
9857         printf( "\tN_UNITDATA_REQ\n" );
9858         break;
9859
9860       case N_UNITDATA_IND:
9861         printf( "\tN_UNITDATA_IND\n" );
9862         break;
9863
9864       default:
9865         (void) printf( "Unknown NPI error %d", primitive->PRIM_type );
9866         return 0;
9867     }
9868 }
9869 #endif /* DEBUG */
9870
9871 /* it looks like signal handling is not needed with streams! */
9872 /* x25oobh()    - handle SIGURG signals - take from isode ? */
9873
9874 #endif /* IBMX25 */
9875
9876 #ifndef NOHTTP
9877 /*
9878   Which time.h files to include... See ckcdeb.h for defaults.
9879   Note that 0, 1, 2, or all 3 of these can be included according to
9880   the symbol definitions.
9881 */
9882 #ifndef NOTIMEH
9883 #ifdef TIMEH
9884 #include <time.h>
9885 #endif /* TIMEH */
9886 #endif /* NOTIMEH */
9887
9888 #ifndef NOSYSTIMEH
9889 #ifdef SYSTIMEH
9890 #include <sys/time.h>
9891 #endif /* SYSTIMEH */
9892 #endif /* NOSYSTIMEH */
9893
9894 #ifndef NOSYSTIMEBH
9895 #ifdef SYSTIMEBH
9896 #include <sys/timeb.h>
9897 #endif /* SYSTIMEBH */
9898 #endif /* NOSYSTIMEBH */
9899
9900 #ifndef TIMEH
9901 #ifndef SYSTIMEH
9902 #ifndef SYSTIMEBH
9903 #ifdef Plan9
9904 #include <sys/time.h>
9905 #else
9906 #ifdef AIX41
9907 #include <time.h>
9908 #else
9909 #ifdef SUNOS4
9910 #include <sys/time.h>
9911 #else
9912 #ifdef SYSTIMEH
9913 #include <sys/time.h>
9914 #else
9915 #ifdef POSIX
9916 #include <posix/time.h>
9917 #else
9918 #ifdef CLIX
9919 #include <sys/time.h>
9920 #else
9921 #ifdef OS2
9922 #include <time.h>
9923 #else
9924 #include <time.h>
9925 /* #include <utime.h> */
9926 #endif /* OS2 */
9927 #endif /* CLIX */
9928 #endif /* POSIX */
9929 #endif /* SYSTIMEH */
9930 #endif /* SUNOS4 */
9931 #endif /* AIX41 */
9932 #endif /* Plan9 */
9933 #endif
9934 #endif
9935 #endif
9936
9937 #ifdef OS2
9938 #include <sys/utime.h>
9939 #ifdef NT
9940 #define utimbuf _utimbuf
9941 #endif /* NT */
9942 #define utime   _utime
9943 #else
9944 #ifdef SYSUTIMEH                        /* <sys/utime.h> if requested,  */
9945 #include <sys/utime.h>                  /* for extra fields required by */
9946 #else                                   /* 88Open spec. */
9947 #ifdef UTIMEH                           /* or <utime.h> if requested */
9948 #include <utime.h>                      /* (SVR4, POSIX) */
9949 #define SYSUTIMEH                       /* Use this for both cases. */
9950 #endif /* UTIMEH */
9951 #endif /* SYSUTIMEH */
9952 #endif /* OS2 */
9953
9954 #ifdef VMS                              /* SMS 2007/02/15 */
9955 #include "ckvrtl.h"
9956 #endif /* def VMS */
9957
9958 #ifndef HTTP_VERSION
9959 #define HTTP_VERSION "HTTP/1.1"
9960 #endif /* HTTP_VERSION */
9961
9962 #ifdef CMDATE2TM
9963 time_t
9964 #ifdef CK_ANSIC
9965 http_date(char * date)
9966 #else
9967 http_date(date) char * date;
9968 #endif /* CK_ANSIC */
9969 /* http_date */ {
9970     /* HTTP dates are of the form:  "Sun, 06 Oct 1997 20:11:47 GMT" */
9971     /* There are two older formats which we are required to parse
9972      * that we currently do not:
9973      *
9974      * RFC 850:   "Sunday, 06-Oct-97 20:11:47 GMT"
9975      * asctime(): "Sun Nov  6 20:11:47 1997"
9976      *
9977      * However, it is required that all dates be sent in the form we
9978      * do accept.  The other two formats are for compatibility with
9979      * really old servers.
9980      */
9981     extern char cmdatebuf[18];
9982     struct tm t_tm;
9983     time_t t;
9984     char ldate[32];
9985     int j;
9986
9987     j = ckindex(",",date,0,0,0);
9988     ckstrncpy(ldate,&date[j+1],25);
9989
9990     {   /*
9991            cmcvtate() date changed to return a string pointer.
9992            fdc, 12 Aug 2001.
9993         */
9994         char * dp;
9995         dp = (char *)cmcvtdate(ldate,0); /* Convert to normal form */
9996         if (!dp)
9997           return(0);
9998         t_tm = *cmdate2tm(dp,1);
9999     }
10000 /*
10001   From Lucas Hart, 5 Dec 2001:
10002   "On the systems to which I have access (SunOS 4.1.1, Solaris 8, and Tru64),
10003   setting tm_isdst to -1 maintains the correct timezone offsets, i.e., writes
10004   the specified (GMT) time if the buffer size is 21, or the contemporaneous
10005   localtime if the buffer size is 25.  Perhaps tm_isdst should be set in
10006   cmdate2tm(), rather than only in http_date."
10007 */
10008 #ifndef NOTM_ISDST                      /* For platforms where */
10009     t_tm.tm_isdst = -1;                 /* tm_isdst doesn't exist. */
10010 #endif /* NOTM_ISDST */
10011
10012     t = mktime(&t_tm);                  /* NOT PORTABLE */
10013
10014 #ifdef XX_TIMEZONE
10015     t -= _timezone;
10016 #endif /* XX_TIMEZONE */
10017
10018     return(t);
10019 }
10020 #endif /* CMDATE2TM */
10021
10022 char *
10023 http_now() {
10024     static char nowstr[32];
10025 #ifdef CMDATE2TM
10026     struct tm  *gmt;
10027     time_t ltime;                       /* NOT PORTABLE */
10028
10029     time(&ltime);
10030
10031     gmt = gmtime(&ltime);               /* PROBABLY NOT PORTABLE */
10032     strftime(nowstr,32,"%a, %d %b %Y %H:%M:%S GMT",gmt); /* NOT PORTABLE */
10033     /* not only is it not portable but it's locale-dependent */
10034 #else
10035 /*
10036   This is hopeless.  First of all, it seems that HTTP wants Day and Month
10037   NAMES?  In English?  Whose idea was that?  Even worse, the date/time must be
10038   expressed in Zulu (UTC (GMT)), and converting from local time to GMT is a
10039   nightmare.  Every platform does it differently, if at all -- even if we
10040   restrict ourselves to UNIX.  For example (quoting from recent C-Kermit edit
10041   history), "Fixed a longstanding bug in the BSDI version, in which incoming
10042   file dates were set in GMT rather than local time.  It seems in 4.4BSD,
10043   localtime() does not return the local time, but rather Zero Meridian (Zulu)
10044   time (GMT), and must be adjusted by the tm_gmtoff value."  Swell.  For
10045   greater appreciation of the scope of the problem, just take a look at the
10046   time-related #ifdefs in ckutio.c.  The only right way to do this is to add
10047   our own portable API for converting between local time and GMT/UTC/Zulu
10048   that shields us not only from UNIXisms like time_t and struct tm, but also
10049   the unbelievable amount of differences in time-related APIs -- e.g. is
10050   "timezone" an external variable or a function; which header file(s) do we
10051   include, etc etc etc.  It's a major project.
10052 */
10053     int x;
10054     x = cmcvtdate("",1);
10055
10056 Evidently this code is not used -- if it is, it must be fixed to use
10057 new (aug 2001) cmcvtdate() calling conventions.
10058
10059     if (x < 0)
10060       return("");
10061 /*  yyyymmdd hh:mm:ss */
10062 /*  01234567890123456 */
10063     nowstr[0]  = 'X';                   /* 1st letter of day */
10064     nowstr[1]  = 'x';                   /* 2nd letter of day */
10065     nowstr[2]  = 'x';                   /* 3rd letter of day */
10066     nowstr[3]  = ',';
10067     nowstr[4]  = ' ';
10068     nowstr[5]  = cmdate[6];
10069     nowstr[6]  = cmdate[7];
10070     nowstr[7]  = ' ';
10071     nowstr[8]  = ' ';                   /* first letter of month */
10072     nowstr[9]  = ' ';                   /* second letter of month */
10073     nowstr[10] = ' ';                   /* third letter of month */
10074     nowstr[11] = ' ';
10075     nowstr[12] = cmdate[0];
10076     nowstr[13] = cmdate[1];
10077     nowstr[14] = cmdate[2];
10078     nowstr[15] = cmdate[3];
10079     nowstr[16] = ' ';
10080     nowstr[17] = cmdate[9];
10081     nowstr[18] = cmdate[10];
10082     nowstr[19] = cmdate[11];
10083     nowstr[20] = cmdate[12];
10084     nowstr[21] = cmdate[13];
10085     nowstr[22] = cmdate[14];
10086     nowstr[23] = cmdate[15];
10087     nowstr[24] = cmdate[16];
10088     nowstr[25] = ' ';
10089     nowstr[26] = 'G';
10090     nowstr[27] = 'M';
10091     nowstr[28] = 'T';
10092     nowstr[29] = '\0';
10093 #endif /* CMDATE2TM */
10094     return(nowstr);
10095 }
10096
10097 #ifndef OS2
10098 #ifndef CK_AUTHENTICATION
10099 /* from ckuusr.h, which this module normally doesn't include */
10100 _PROTOTYP( int dclarray, (char, int) );
10101 #endif /* CK_AUTHENTICATION */
10102 #endif /* OS2 */
10103 /*
10104   Assign http response pairs to given array.
10105   For best results, response pairs should contain no spaces.
10106
10107   Call with:
10108     resp  =  pointer to response list.
10109     n     =  size of response list.
10110     array =  array letter.
10111   Returns:
10112     0 on failure.
10113     >= 1, size of array, on success.
10114 */
10115 static int
10116 #ifdef CK_ANSIC
10117 http_mkarray(char ** resp, int n, char array)
10118 #else
10119 http_mkarray(resp, n, array) char ** resp; int n; char array;
10120 #endif /* CK_ANSIC */
10121 {
10122 #ifndef NOSPL
10123     int i, x;
10124     char ** ap;
10125     extern char ** a_ptr[];
10126     extern int a_dim[];
10127
10128     if (!array || n <= 0)
10129       return(0);
10130     if ((x = dclarray(array,n)) < 0) {
10131         printf("?Array declaration failure\n");
10132         return(-9);
10133     }
10134     /* Note: argument array is 0-based but Kermit array is 1-based */
10135     ap = a_ptr[x];
10136     ap[0] = NULL;                       /* 0th element is empty */
10137     for (i = 1; i <= n; i++) {
10138         ap[i] = resp[i-1];              /* If resp elements were malloc'd */
10139         resp[i-1] = NULL;
10140     }
10141     a_dim[x] = n;
10142     return(n);
10143 #else
10144     return(0);
10145 #endif /* NOSPL */
10146 }
10147
10148 #define HTTPHEADCNT 64
10149 int
10150 http_get_chunk_len()
10151 {
10152     int len = 0;
10153     int i = 0, j = -1;
10154     char buf[24];
10155     int ch;
10156
10157     while ((ch = http_inc(0)) >= 0 && i < 24) {
10158         buf[i] = ch;
10159         if ( buf[i] == ';' )            /* Find chunk-extension (if any) */
10160             j = i;
10161         if ( buf[i] == 10 ) {           /* found end of line */
10162             if (i > 0 && buf[i-1] == 13)
10163                 i--;
10164             buf[i] = '\0';
10165             break;
10166         }
10167         i++;
10168     }
10169     if ( i < 24 ) {                     /* buf now contains len in Hex */
10170         len = hextoulong(buf, j == -1 ? i : j-1);
10171     }
10172
10173     return(len);
10174 }
10175
10176 int
10177 http_isconnected()
10178 {
10179     return(httpfd != -1);
10180 }
10181
10182 char *
10183 http_host()
10184 {
10185     return(httpfd != -1 ? http_host_port : "");
10186 }
10187
10188 char *
10189 http_security()
10190 {
10191     if ( httpfd == -1 )
10192         return("NULL");
10193 #ifdef CK_SSL
10194     if (tls_http_active_flag) {
10195         SSL_CIPHER * cipher;
10196         const char *cipher_list;
10197         static char buf[128];
10198         buf[0] = NUL;
10199         cipher = SSL_get_current_cipher(tls_http_con);
10200         cipher_list = SSL_CIPHER_get_name(cipher);
10201         SSL_CIPHER_description(cipher,buf,sizeof(buf));
10202         return(buf);
10203     }
10204 #endif /* CK_SSL */
10205     return("NULL");
10206 }
10207
10208 int
10209 http_reopen()
10210 {
10211     int rc = 0;
10212     char * s = NULL;                    /* strdup is not portable */
10213     if ( tcp_http_proxy ) {
10214         char * p;
10215         makestr(&s,(char *)http_host_port);
10216         p = s;
10217         while (*p != '\0' && *p != ':') p++; /* Look for colon */
10218         if (*p == ':') {                     /* Have a colon */
10219             *p++ = '\0';                     /* Get service name or number */
10220         } else {
10221             p="http";
10222         }
10223         rc = http_open(s,p,http_ssl,NULL,0,http_agent);
10224     } else {
10225         makestr(&s,(char *)http_ip);
10226         rc = http_open(s,ckuitoa(http_port),http_ssl,NULL,0,http_agent);
10227     }
10228     free(s);
10229     return(rc);
10230 }
10231
10232
10233 int
10234 #ifdef CK_ANSIC
10235 http_open(char * hostname, char * svcname, int use_ssl, char * rdns_name,
10236           int rdns_len, char * agent)
10237 #else /* CK_ANSIC */
10238 http_open(hostname, svcname, use_ssl, rdns_name, rdns_len, agent)
10239     char * hostname;
10240     char * svcname;
10241     int    use_ssl;
10242     char * rdns_name;
10243     int    rdns_len;
10244     char * agent;
10245 #endif /* CK_ANSIC */
10246 {
10247     char namecopy[NAMECPYL];
10248     char *p;
10249     int i, x, dns = 0;
10250 #ifdef TCPSOCKET
10251     int isconnect = 0;
10252 #ifdef SO_OOBINLINE
10253     int on = 1;
10254 #endif /* SO_OOBINLINE */
10255     struct servent *service=NULL;
10256     struct hostent *host=NULL;
10257     struct sockaddr_in r_addr;
10258     struct sockaddr_in sin;
10259     struct sockaddr_in l_addr;
10260     GSOCKNAME_T l_slen;
10261 #ifdef EXCELAN
10262     struct sockaddr_in send_socket;
10263 #endif /* EXCELAN */
10264
10265 #ifdef INADDRX
10266 /* inet_addr() is of type struct in_addr */
10267 #ifdef datageneral
10268     extern struct in_addr inet_addr();
10269 #else
10270 #ifdef HPUX5WINTCP
10271     extern struct in_addr inet_addr();
10272 #endif /* HPUX5WINTCP */
10273 #endif /* datageneral */
10274     struct in_addr iax;
10275 #else
10276 #ifdef INADDR_NONE
10277     struct in_addr iax;
10278 #else /* INADDR_NONE */
10279     long iax;
10280 #endif /* INADDR_NONE */
10281 #endif /* INADDRX */
10282
10283     if ( rdns_name == NULL || rdns_len < 0 )
10284         rdns_len = 0;
10285
10286     *http_ip = '\0';                     /* Initialize IP address string */
10287     namecopy[0] = '\0';
10288
10289 #ifdef DEBUG
10290     if (deblog) {
10291         debug(F110,"http_open hostname",hostname,0);
10292         debug(F110,"http_open svcname",svcname,0);
10293     }
10294 #endif /* DEBUG */
10295     if (!hostname) hostname = "";
10296     if (!svcname) svcname = "";
10297     if (!*hostname || !*svcname) return(-1);
10298
10299     
10300     service = ckgetservice(hostname,svcname,http_ip,20);
10301
10302     if (service == NULL) {
10303         if ( !quiet )
10304             printf("?Invalid service: %s\r\n",svcname);
10305         return(-1);
10306     }
10307
10308     /* For HTTP connections we must preserve the original hostname and */
10309     /* service requested so we can include them in the Host header.    */
10310     ckmakmsg(http_host_port,sizeof(http_host_port),hostname,":",
10311               ckuitoa(ntohs(service->s_port)),NULL);
10312     http_port = ntohs(service->s_port);
10313     http_ssl = use_ssl;
10314     debug(F111,"http_open",http_host_port,http_port);
10315
10316     /* 'http_ip' contains the IP address to which we want to connect        */
10317     /* 'svcnam'   contains the service name                                 */
10318     /* 'service->s_port' contains the port number in network byte order     */
10319
10320     /* If we are using an http proxy, we need to create a buffer containing */
10321     /*   hostname:port-number                                               */
10322     /* to pass to the http_connect() function.  Then we need to replace     */
10323     /* 'namecopy' with the name of the proxy server and the service->s_port */
10324     /* with the port number of the proxy (default port 80).                 */
10325
10326     if ( tcp_http_proxy ) {
10327
10328         ckmakmsg(proxycopy,sizeof(proxycopy),hostname,":",
10329                  ckuitoa(ntohs(service->s_port)),NULL);
10330         ckstrncpy(namecopy,tcp_http_proxy,NAMECPYL);
10331
10332         p = namecopy;                       /* Was a service requested? */
10333         while (*p != '\0' && *p != ':') p++; /* Look for colon */
10334         if (*p == ':') {                    /* Have a colon */
10335             debug(F110,"http_open name has colon",namecopy,0);
10336             *p++ = '\0';                    /* Get service name or number */
10337         } else {
10338             strcpy(++p,"http");
10339         }
10340
10341         service = ckgetservice(namecopy,p,http_ip,20);
10342         if (!service) {
10343             fprintf(stderr, "Can't find port for service %s\n", p);
10344 #ifdef TGVORWIN
10345             debug(F101,"http_open can't get service for proxy","",socket_errno);
10346 #else
10347             debug(F101,"http_open can't get service for proxy","",errno);
10348 #endif /* TGVORWIN */
10349             errno = 0;                  /* (rather than mislead) */
10350             return(-1);
10351         }
10352
10353         /* copy the proxyname and remove the service if any so we can use 
10354          * it as the hostname 
10355          */
10356         ckstrncpy(namecopy,tcp_http_proxy,NAMECPYL);
10357         p = namecopy;                       /* Was a service requested? */
10358         while (*p != '\0' && *p != ':') p++; /* Look for colon */
10359         if (*p == ':') {                    /* Have a colon */
10360             *p = '\0';                      /* terminate string */
10361         }        
10362         hostname = namecopy;                /* use proxy as hostname */
10363     }
10364
10365     /* Set up socket structure and get host address */
10366     bzero((char *)&r_addr, sizeof(r_addr));
10367     debug(F100,"http_open bzero ok","",0);
10368
10369 #ifdef INADDR_NONE
10370     debug(F101,"http_open INADDR_NONE defined","",INADDR_NONE);
10371 #else /* INADDR_NONE */
10372     debug(F100,"http_open INADDR_NONE not defined","",0);
10373 #endif /* INADDR_NONE */
10374 #ifdef INADDRX
10375     debug(F100,"http_open INADDRX defined","",0);
10376 #else /* INADDRX */
10377     debug(F100,"http_open INADDRX not defined","",0);
10378 #endif /* INADDRX */
10379
10380 #ifndef NOMHHOST
10381 #ifdef INADDRX
10382     iax = inet_addr(http_ip[0]?http_ip:hostname);
10383     debug(F111,"http_open inet_addr",http_ip[0]?http_ip:hostname,iax.s_addr);
10384 #else /* INADDRX */
10385 #ifdef INADDR_NONE
10386     iax.s_addr = inet_addr(http_ip[0]?http_ip:hostname);
10387     debug(F111,"http_open inet_addr",http_ip[0]?http_ip:hostname,iax.s_addr);
10388 #else /* INADDR_NONE */
10389 #ifndef datageneral
10390     iax = (unsigned int) inet_addr(http_ip[0]?http_ip:hostname);
10391 #else
10392     iax = -1L;
10393 #endif /* datageneral */
10394     debug(F111,"http_open inet_addr",http_ip[0]?http_ip:hostname,iax);
10395 #endif /* INADDR_NONE */
10396 #endif /* INADDRX */
10397
10398     dns = 0;
10399     if (
10400 #ifdef INADDR_NONE
10401 /* This might give warnings on 64-bit platforms but they should be harmless */
10402 /* because INADDR_NONE should be all 1's anyway, thus the OR part is */
10403 /* probably superfluous -- not sure why it's even there, maybe it should be */
10404 /* removed. */
10405         iax.s_addr == INADDR_NONE /* || iax.s_addr == (unsigned long) -1L */
10406 #else /* INADDR_NONE */
10407         iax == -1
10408 #endif /* INADDR_NONE */
10409         ) {
10410         if (!quiet) {
10411             printf(" DNS Lookup... ");
10412             fflush(stdout);
10413         }
10414         if ((host = gethostbyname(http_ip[0] ? http_ip : hostname)) != NULL) {
10415             debug(F100,"http_open gethostbyname != NULL","",0);
10416             host = ck_copyhostent(host);
10417             dns = 1;                    /* Remember we performed dns lookup */
10418             r_addr.sin_family = host->h_addrtype;
10419             if (tcp_rdns && host->h_name && host->h_name[0] && (rdns_len > 0)
10420                  && (tcp_http_proxy == NULL)
10421                  )
10422                 ckmakmsg(rdns_name,rdns_len,host->h_name,":",svcname,NULL);
10423
10424 #ifdef HADDRLIST
10425 #ifdef h_addr
10426             /* This is for trying multiple IP addresses - see <netdb.h> */
10427             if (!(host->h_addr_list))
10428               return(-1);
10429             bcopy(host->h_addr_list[0],
10430                   (caddr_t)&r_addr.sin_addr,
10431                   host->h_length
10432                   );
10433 #else
10434             bcopy(host->h_addr, (caddr_t)&r_addr.sin_addr, host->h_length);
10435 #endif /* h_addr */
10436 #else  /* HADDRLIST */
10437             bcopy(host->h_addr, (caddr_t)&r_addr.sin_addr, host->h_length);
10438 #endif /* HADDRLIST */
10439 #ifdef COMMENT
10440 #ifndef EXCELAN
10441             debug(F111,"BCOPY","host->h_addr",host->h_addr);
10442 #endif /* EXCELAN */
10443             debug(F111,"BCOPY"," (caddr_t)&r_addr.sin_addr",
10444                   (caddr_t)&r_addr.sin_addr);
10445             debug(F111,"BCOPY"," r_addr.sin_addr.s_addr",
10446                   r_addr.sin_addr.s_addr);
10447 #endif  /* COMMENT */
10448             debug(F111,"BCOPY","host->h_length",host->h_length);
10449         }
10450     }
10451 #endif /* NOMHHOST */
10452
10453     if (!dns) {
10454 #ifdef INADDRX
10455 /* inet_addr() is of type struct in_addr */
10456         struct in_addr ina;
10457         unsigned long uu;
10458         debug(F100,"http_open gethostbyname == NULL: INADDRX","",0);
10459         ina = inet_addr(http_ip[0]?http_ip:hostname);
10460         uu = *(unsigned int *)&ina;
10461 #else /* Not INADDRX */
10462 /* inet_addr() is unsigned long */
10463         unsigned long uu;
10464         debug(F100,"http_open gethostbyname == NULL: Not INADDRX","",0);
10465         uu = inet_addr(http_ip[0]?http_ip:hostname);
10466 #endif /* INADDRX */
10467         debug(F101,"http_open uu","",uu);
10468         if (
10469 #ifdef INADDR_NONE
10470             !(uu == INADDR_NONE || uu == (unsigned int) -1L)
10471 #else   /* INADDR_NONE */
10472             uu != ((unsigned long)-1)
10473 #endif /* INADDR_NONE */
10474             ) {
10475             r_addr.sin_addr.s_addr = uu;
10476             r_addr.sin_family = AF_INET;
10477         } else {
10478 #ifdef VMS
10479             fprintf(stdout, "\r\n");    /* complete any previous message */
10480 #endif /* VMS */
10481             fprintf(stderr, "Can't get address for %s\n",
10482                      http_ip[0]?http_ip:hostname);
10483 #ifdef TGVORWIN
10484             debug(F101,"http_open can't get address","",socket_errno);
10485 #else
10486             debug(F101,"http_open can't get address","",errno);
10487 #endif /* TGVORWIN */
10488             errno = 0;                  /* Rather than mislead */
10489             return(-1);
10490         }
10491     }
10492
10493     /* Get a file descriptor for the connection. */
10494
10495     r_addr.sin_port = service->s_port;
10496     ckstrncpy(http_ip,(char *)inet_ntoa(r_addr.sin_addr),20);
10497     debug(F110,"http_open trying",http_ip,0);
10498     if (!quiet && *http_ip) {
10499         printf(" Trying %s... ", http_ip);
10500         fflush(stdout);
10501     }
10502
10503     /* Loop to try additional IP addresses, if any. */
10504
10505     do {
10506 #ifdef EXCELAN
10507         send_socket.sin_family = AF_INET;
10508         send_socket.sin_addr.s_addr = 0;
10509         send_socket.sin_port = 0;
10510         if ((httpfd = socket(SOCK_STREAM, (struct sockproto *)0,
10511                             &send_socket, SO_REUSEADDR)) < 0)
10512 #else  /* EXCELAN */
10513         if ((httpfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
10514 #endif /* EXCELAN */
10515             {
10516 #ifdef EXCELAN
10517                 experror("TCP socket error");
10518 #else
10519 #ifdef TGVORWIN
10520 #ifdef OLD_TWG
10521                 errno = socket_errno;
10522 #endif /* OLD_TWG */
10523                 socket_perror("TCP socket error");
10524                 debug(F101,"http_open socket error","",socket_errno);
10525 #else
10526                 perror("TCP socket error");
10527                 debug(F101,"http_open socket error","",errno);
10528 #endif /* TGVORWIN */
10529 #endif /* EXCELAN */
10530                 return (-1);
10531             }
10532         errno = 0;
10533
10534        /* If a specific TCP address on the local host is desired we */
10535        /* must bind it to the socket.                               */
10536 #ifndef datageneral
10537          if (tcp_address) {
10538              int s_errno;
10539
10540              debug(F110,"http_open binding socket to",tcp_address,0);
10541              bzero((char *)&sin,sizeof(sin));
10542              sin.sin_family = AF_INET;
10543 #ifdef INADDRX
10544              inaddrx = inet_addr(tcp_address);
10545              sin.sin_addr.s_addr = *(unsigned long *)&inaddrx;
10546 #else
10547              sin.sin_addr.s_addr = inet_addr(tcp_address);
10548 #endif /* INADDRX */
10549              sin.sin_port = 0;
10550              if (bind(httpfd, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
10551                  s_errno = socket_errno; /* Save error code */
10552 #ifdef TCPIPLIB
10553                  socket_close(httpfd);
10554 #else /* TCPIPLIB */
10555                  close(httpfd);
10556 #endif /* TCPIPLIB */
10557                  httpfd = -1;
10558                  errno = s_errno;       /* and report this error */
10559                  debug(F101,"http_open bind errno","",errno);
10560                  return(-1);
10561              }
10562          }
10563 #endif /* datageneral */
10564
10565 /* Now connect to the socket on the other end. */
10566
10567 #ifdef EXCELAN
10568         if (connect(httpfd, &r_addr) < 0)
10569 #else
10570 #ifdef NT
10571           WSASafeToCancel = 1;
10572 #endif /* NT */
10573         if (connect(httpfd, (struct sockaddr *)&r_addr, sizeof(r_addr)) < 0)
10574 #endif /* EXCELAN */
10575           {
10576 #ifdef NT
10577               WSASafeToCancel = 0;
10578 #endif /* NT */
10579 #ifdef OS2
10580               i = socket_errno;
10581 #else /* OS2 */
10582 #ifdef TGVORWIN
10583               i = socket_errno;
10584 #else
10585               i = errno;                /* Save error code */
10586 #endif /* TGVORWIN */
10587 #endif /* OS2 */
10588 #ifdef HADDRLIST
10589 #ifdef h_addr
10590               if (host && host->h_addr_list && host->h_addr_list[1]) {
10591                   perror("");
10592                   host->h_addr_list++;
10593                   bcopy(host->h_addr_list[0],
10594                         (caddr_t)&r_addr.sin_addr,
10595                         host->h_length);
10596
10597                   ckstrncpy(http_ip,(char *)inet_ntoa(r_addr.sin_addr),20);
10598                   debug(F110,"http_open h_addr_list",http_ip,0);
10599                   if (!quiet && *http_ip) {
10600                       printf(" Trying %s... ", http_ip);
10601                       fflush(stdout);
10602                   }
10603 #ifdef TCPIPLIB
10604                   socket_close(httpfd); /* Close it. */
10605 #else
10606                   close(httpfd);
10607 #endif /* TCPIPLIB */
10608                   continue;
10609               }
10610 #endif /* h_addr */
10611 #endif  /* HADDRLIST */
10612               http_close();
10613               httpfd = -1;
10614               errno = i;                /* And report this error */
10615 #ifdef EXCELAN
10616               if (errno) experror("http_open connect");
10617 #else
10618 #ifdef TGVORWIN
10619               debug(F101,"http_open connect error","",socket_errno);
10620               /* if (errno) socket_perror("http_open connect"); */
10621 #ifdef OLD_TWG
10622               errno = socket_errno;
10623 #endif /* OLD_TWG */
10624               if (!quiet)
10625                 socket_perror("http_open connect");
10626 #else /* TGVORWIN */
10627               debug(F101,"http_open connect errno","",errno);
10628 #ifdef VMS
10629               if (!quiet)
10630                 perror("\r\nFailed");
10631 #else
10632               if (!quiet)
10633                 perror("Failed");
10634 #endif /* VMS */
10635 #ifdef DEC_TCPIP
10636               if (!quiet)
10637                 perror("http_open connect");
10638 #endif /* DEC_TCPIP */
10639 #ifdef CMU_TCPIP
10640               if (!quiet)
10641                 perror("http_open connect");
10642 #endif /* CMU_TCPIP */
10643 #endif /* TGVORWIN */
10644 #endif /* EXCELAN */
10645               return(-1);
10646           }
10647 #ifdef NT
10648         WSASafeToCancel = 0;
10649 #endif /* NT */
10650         isconnect = 1;
10651     } while (!isconnect);
10652
10653 #ifdef NON_BLOCK_IO
10654     on = 1;
10655     x = socket_ioctl(httpfd,FIONBIO,&on);
10656     debug(F101,"http_open FIONBIO","",x);
10657 #endif /* NON_BLOCK_IO */
10658
10659     /* We have succeeded in connecting to the HTTP PROXY.  So now we   */
10660     /* need to attempt to connect through the proxy to the actual host */
10661     /* If that is successful, we have to pretend that we made a direct */
10662     /* connection to the actual host.                                  */
10663
10664     if ( tcp_http_proxy ) {
10665 #ifdef OS2
10666         if (!agent) 
10667           agent = "Kermit 95";  /* Default user agent */
10668 #else
10669         if (!agent) 
10670           agent = "C-Kermit";
10671 #endif /* OS2 */
10672
10673         if (http_connect(httpfd,
10674                          tcp_http_proxy_agent ? tcp_http_proxy_agent : agent,
10675                          NULL,
10676                          tcp_http_proxy_user,
10677                          tcp_http_proxy_pwd,
10678                          0,
10679                          proxycopy
10680                          ) < 0) {
10681             http_close();
10682             return(-1);
10683         }
10684     }
10685
10686 #ifdef SO_OOBINLINE
10687     /* See note on SO_OOBINLINE in netopen() */
10688 #ifdef datageneral
10689     setsockopt(httpfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
10690 #else
10691 #ifdef BSD43
10692     setsockopt(httpfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
10693 #else
10694 #ifdef OSF1
10695     setsockopt(httpfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
10696 #else
10697 #ifdef POSIX
10698     setsockopt(httpfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
10699 #else
10700 #ifdef MOTSV88R4
10701     setsockopt(httpfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
10702 #else
10703 #ifdef SOLARIS
10704 /*
10705   Maybe this applies to all SVR4 versions, but the other (else) way has been
10706   compiling and working fine on all the others, so best not to change it.
10707 */
10708     setsockopt(httpfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
10709 #else
10710 #ifdef OSK
10711     setsockopt(httpfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
10712 #else
10713 #ifdef OS2
10714     {
10715         int rc;
10716         rc = setsockopt(httpfd,
10717                         SOL_SOCKET,
10718                         SO_OOBINLINE,
10719                         (char *) &on,
10720                         sizeof on
10721                         );
10722         debug(F111,"setsockopt SO_OOBINLINE",on ? "on" : "off" ,rc);
10723     }
10724 #else
10725 #ifdef VMS /* or, at least, VMS with gcc */
10726     setsockopt(httpfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
10727 #else
10728 #ifdef CLIX
10729     setsockopt(httpfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
10730 #else
10731     setsockopt(httpfd, SOL_SOCKET, SO_OOBINLINE, &on, sizeof on);
10732 #endif /* CLIX */
10733 #endif /* VMS */
10734 #endif /* OS2 */
10735 #endif /* OSK */
10736 #endif /* SOLARIS */
10737 #endif /* MOTSV88R4 */
10738 #endif /* POSIX */
10739 #endif /* BSD43 */
10740 #endif /* OSF1 */
10741 #endif /* datageneral */
10742 #endif /* SO_OOBINLINE */
10743
10744 #ifndef NOTCPOPTS
10745 #ifndef datageneral
10746 #ifdef SOL_SOCKET
10747 #ifdef TCP_NODELAY
10748     no_delay(ttyfd,tcp_nodelay);
10749 #endif /* TCP_NODELAY */
10750 #ifdef SO_KEEPALIVE
10751     keepalive(ttyfd,tcp_keepalive);
10752 #endif /* SO_KEEPALIVE */
10753 #ifdef SO_LINGER
10754     ck_linger(ttyfd,tcp_linger, tcp_linger_tmo);
10755 #endif /* SO_LINGER */
10756 #ifdef SO_SNDBUF
10757     sendbuf(ttyfd,tcp_sendbuf);
10758 #endif /* SO_SNDBUF */
10759 #ifdef SO_RCVBUF
10760     recvbuf(ttyfd,tcp_recvbuf);
10761 #endif /* SO_RCVBUF */
10762 #endif /* SOL_SOCKET */
10763 #endif /* datageneral */
10764 #endif /* NOTCPOPTS */
10765
10766 #ifndef datageneral
10767     /* Find out our own IP address. */
10768     /* We need the l_addr structure for [E]KLOGIN. */
10769     l_slen = sizeof(l_addr);
10770     bzero((char *)&l_addr, l_slen);
10771 #ifndef EXCELAN
10772     if (!getsockname(httpfd, (struct sockaddr *)&l_addr, &l_slen)) {
10773         char * s = (char *)inet_ntoa(l_addr.sin_addr);
10774         ckstrncpy(myipaddr, s, 20);
10775         debug(F110,"getsockname",myipaddr,0);
10776     }
10777 #endif /* EXCELAN */
10778 #endif /* datageneral */
10779
10780 /* See note in netopen() on Reverse DNS lookups */
10781      if (tcp_rdns == SET_ON) {
10782 #ifdef NT
10783         if (isWin95())
10784           sleep(1);
10785 #endif /* NT */
10786         if (!quiet) {
10787             printf(" Reverse DNS Lookup... ");
10788             fflush(stdout);
10789         }
10790         if (host = gethostbyaddr((char *)&r_addr.sin_addr,4,PF_INET)) {
10791             char * s;
10792             host = ck_copyhostent(host);
10793             debug(F100,"http_open gethostbyname != NULL","",0);
10794             if (!quiet) {
10795                 printf("(OK)\n");
10796                 fflush(stdout);
10797             }
10798             s = host->h_name;
10799             if (!s) {                   /* This can happen... */
10800                 debug(F100,"http_open host->h_name is NULL","",0);
10801                 s = "";
10802             }
10803             /* Something is wrong with inet_ntoa() on HPUX 10.xx */
10804             /* The compiler says "Integral value implicitly converted to */
10805             /* pointer in assignment."  The prototype is right there */
10806             /* in <arpa/inet.h> so what's the problem? */
10807             /* Ditto in HP-UX 5.x, but not 8.x or 9.x... */
10808             if (!*s) {                  /* No name so substitute the address */
10809                 debug(F100,"http_open host->h_name is empty","",0);
10810                 s = inet_ntoa(r_addr.sin_addr); /* Convert address to string */
10811                 if (!s)                 /* Trust No 1 */
10812                   s = "";
10813                 if (*s) {               /* If it worked, use this string */
10814                     ckstrncpy(http_ip,s,20);
10815                 }
10816                 s = http_ip;             /* Otherwise stick with the IP */
10817                 if (!*s)                 /* or failing that */
10818                   s = http_host_port;    /* the name we were called with. */
10819             }
10820             if (*s)                     /* return the rdns name */
10821                 ckmakmsg(rdns_name,rdns_len,s,":",svcname,NULL);
10822
10823             if (!quiet && *s
10824 #ifndef NOICP
10825                 && !doconx
10826 #endif /* NOICP */
10827                 ) {
10828                 printf(" %s connected on port %s\n",s,
10829                        ckuitoa(ntohs(service->s_port)));
10830 #ifdef BETADEBUG
10831                 /* This is simply for testing the DNS entries */
10832                 if (host->h_aliases) {
10833                     char ** a = host->h_aliases;
10834                     while (*a) {
10835                         printf(" alias => %s\n",*a);
10836                         a++;
10837                     }
10838                 }
10839 #endif /* BETADEBUG */
10840             }
10841         } else {
10842             if (!quiet) printf("Failed.\n");
10843         }
10844     } else if (!quiet) printf("(OK)\n");
10845     if (!quiet) fflush(stdout);
10846
10847
10848     if ( tcp_http_proxy ) {
10849         /* Erase the IP address since we cannot reuse it */
10850         http_ip[0] = '\0';
10851     } else {
10852         /* This should already have been done but just in case */
10853         ckstrncpy(http_ip,(char *)inet_ntoa(r_addr.sin_addr),20);
10854     }
10855     makestr(&http_agent,agent);
10856
10857 #ifdef CK_SSL
10858     if (use_ssl && ck_ssleay_is_installed()) {
10859         if (!ssl_http_init(hostname)) {
10860             if (bio_err!=NULL) {
10861                 BIO_printf(bio_err,"ssl_tn_init() failed\n");
10862                 ERR_print_errors(bio_err);
10863             } else {
10864                 fflush(stderr);
10865                 fprintf(stderr,"ssl_tn_init() failed\n");
10866                 ERR_print_errors_fp(stderr);
10867             }
10868             http_close();
10869             return(-1);
10870         } else if ( ck_ssl_http_client(httpfd,hostname) < 0 ) {
10871             http_close();
10872             return(-1);
10873         }
10874     }
10875 #endif /* CK_SSL */
10876 #endif /* TCPSOCKET */
10877
10878     return(0);                          /* Done. */
10879 }
10880
10881 int
10882 #ifdef CK_ANSIC
10883 http_close(VOID)
10884 #else /* CK_ANSIC */
10885 http_close()
10886 #endif /* CK_ANSIC */
10887 {
10888     int x = 0;
10889     debug(F101,"http_close","",httpfd);
10890
10891 #ifdef HTTP_BUFFERING
10892     http_count = 0;
10893     http_bufp = 0;
10894 #endif  /* HTTP_BUFFERING */
10895
10896     if (httpfd == -1)                    /* Was open? */
10897       return(0);                        /* Wasn't. */
10898
10899 #ifndef OS2
10900     if (httpfd > -1)                     /* Was. */
10901 #endif /* OS2 */
10902       {
10903 #ifdef CK_SSL
10904           if (tls_http_active_flag) {
10905               if (ssl_debug_flag)
10906                 BIO_printf(bio_err,"calling SSL_shutdown\n");
10907               SSL_shutdown(tls_http_con);
10908               tls_http_active_flag = 0;
10909           }
10910 #endif /* CK_SSL */
10911 #ifdef TCPIPLIB
10912           x = socket_close(httpfd);      /* Close it. */
10913 #else
10914 #ifndef OS2
10915           x = close(httpfd);
10916 #endif /* OS2 */
10917 #endif /* TCPIPLIB */
10918       }
10919     httpfd = -1;                          /* Mark it as closed. */
10920     /* do not erase http_host_port, http_ip, http_port so they */
10921     /* can be used by http_reopen() */
10922     return(x);
10923 }
10924
10925
10926 /* http_tol()
10927  * Call with s = pointer to string, n = length.
10928  * Returns number of bytes actually written on success, or
10929  * -1 on i/o error, -2 if called improperly.
10930  */
10931
10932 int
10933 http_tol(s,n) CHAR *s; int n; {
10934     int count = 0;
10935     int len = n;
10936     int try = 0;
10937
10938     if (httpfd == -1) {
10939         debug(F100,"http_tol socket is closed","",0);
10940         return -1;
10941     }
10942     debug(F101,"http_tol TCPIPLIB ttnet","",ttnet);
10943 #ifdef COMMENT
10944     ckhexdump("http_tol",s,n);
10945 #endif /* COMMENT */
10946
10947 #ifdef CK_SSL
10948     if (tls_http_active_flag) {
10949         int error, r;
10950         /* Write using SSL */
10951       ssl_retry:
10952           r = SSL_write(tls_http_con, s, len /* >1024?1024:len */);
10953         switch (SSL_get_error(tls_http_con,r)) {
10954           case SSL_ERROR_NONE:
10955             debug(F111,"http_tol","SSL_write",r);
10956             if ( r == len )
10957                 return(n);
10958              s += r;
10959              len -= r;
10960              goto ssl_retry;
10961           case SSL_ERROR_WANT_WRITE:
10962             debug(F100,"http_tol SSL_ERROR_WANT_WRITE","",0);
10963               return(-1);
10964           case SSL_ERROR_WANT_READ:
10965             debug(F100,"http_tol SSL_ERROR_WANT_READ","",0);
10966             return(-1);
10967           case SSL_ERROR_SYSCALL:
10968               if ( r == 0 ) { /* EOF */
10969                   http_close();
10970                   return(-2);
10971               } else {
10972                   int rc = -1;
10973 #ifdef NT
10974                   int gle = GetLastError();
10975                   debug(F111,"http_tol SSL_ERROR_SYSCALL",
10976                          "GetLastError()",gle);
10977                   rc = os2socketerror(gle);
10978                   if (rc == -1)
10979                       rc = -2;
10980                   else if ( rc == -2 )
10981                       return -1;
10982 #endif /* NT */
10983                   return(rc);
10984               }
10985           case SSL_ERROR_WANT_X509_LOOKUP:
10986             debug(F100,"http_tol SSL_ERROR_WANT_X509_LOOKUP","",0);
10987             http_close();
10988             return(-2);
10989           case SSL_ERROR_SSL:
10990             debug(F100,"http_tol SSL_ERROR_SSL","",0);
10991             http_close();
10992             return(-2);
10993           case SSL_ERROR_ZERO_RETURN:
10994             debug(F100,"http_tol SSL_ERROR_ZERO_RETURN","",0);
10995             http_close();
10996             return(-2);
10997           default:
10998             debug(F100,"http_tol SSL_ERROR_?????","",0);
10999             http_close();
11000             return(-2);
11001         }
11002     }
11003 #endif /* CK_SSL */
11004
11005   http_tol_retry:
11006     try++;                              /* Increase the try counter */
11007
11008     {
11009 #ifdef BSDSELECT
11010         fd_set wfds;
11011         struct timeval tv;
11012
11013         debug(F101,"http_tol BSDSELECT","",0);
11014         tv.tv_usec = 0L;
11015         tv.tv_sec=30;
11016 #ifdef NT
11017         WSASafeToCancel = 1;
11018 #endif /* NT */
11019 #ifdef STREAMING
11020       do_select:
11021 #endif /* STREAMING */
11022         FD_ZERO(&wfds);
11023         FD_SET(httpfd, &wfds);
11024         if (select(FD_SETSIZE, NULL,
11025 #ifdef __DECC
11026 #ifndef __DECC_VER
11027                     (int *)
11028 #endif /* __DECC_VER */
11029 #endif /* __DECC */
11030                    &wfds, NULL, &tv) < 0) {
11031             int s_errno = socket_errno;
11032             debug(F101,"http_tol select failed","",s_errno);
11033 #ifdef BETADEBUG
11034             printf("http_tol select failed: %d\n", s_errno);
11035 #endif /* BETADEBUG */
11036 #ifdef NT
11037             WSASafeToCancel = 0;
11038             if (!win95selectbug)
11039 #endif /* NT */
11040               return(-1);
11041         }
11042         if (!FD_ISSET(httpfd, &wfds)) {
11043 #ifdef STREAMING
11044             if (streaming)
11045               goto do_select;
11046 #endif /* STREAMING */
11047             debug(F111,"http_tol","!FD_ISSET",ttyfd);
11048 #ifdef NT
11049             WSASafeToCancel = 0;
11050             if (!win95selectbug)
11051 #endif /* NT */
11052               return(-1);
11053         }
11054 #ifdef NT
11055         WSASafeToCancel = 0;
11056 #endif /* NT */
11057 #else /* BSDSELECT */
11058 #ifdef IBMSELECT
11059         {
11060             int tries = 0;
11061             debug(F101,"http_tol IBMSELECT","",0);
11062             while (select(&httpfd, 0, 1, 0, 1000) != 1) {
11063                 int count;
11064                 if (tries++ >= 60) {
11065                     /* if after 60 seconds we can't get permission to write */
11066                     debug(F101,"http_tol select failed","",socket_errno);
11067                     return(-1);
11068                 }
11069 #ifdef COMMENT
11070                 if ((count = http_tchk()) < 0) {
11071                     debug(F111,"http_tol","http_tchk()",count);
11072                     return(count);
11073                 }
11074 #endif /* COMMENT */
11075             }
11076         }
11077 #endif /* IBMSELECT */
11078 #endif /* BSDSELECT */
11079 #ifdef TCPIPLIB
11080         if ((count = socket_write(httpfd,s,n)) < 0) {
11081             int s_errno = socket_errno; /* maybe a function */
11082             debug(F101,"http_tol socket_write error","",s_errno);
11083 #ifdef OS2
11084             if (os2socketerror(s_errno) < 0)
11085               return(-2);
11086 #endif /* OS2 */
11087             return(-1);                 /* Call it an i/o error */
11088         }
11089 #else /* TCPIPLIB */
11090         if ((count = write(httpfd,s,n)) < 0) {
11091             debug(F101,"http_tol socket_write error","",errno);
11092             return(-1);                 /* Call it an i/o error */
11093         }
11094 #endif /* TCPIPLIB */
11095         if (count < n) {
11096             debug(F111,"http_tol socket_write",s,count);
11097             if (try > 25) {
11098                 /* don't try more than 25 times */
11099                 debug(F100,"http_tol tried more than 25 times","",0);
11100                 return(-1);
11101             }
11102             if (count > 0) {
11103                 s += count;
11104                 n -= count;
11105             }
11106             debug(F111,"http_tol retry",s,n);
11107             goto http_tol_retry;
11108         } else {
11109             debug(F111,"http_tol socket_write",s,count);
11110             return(len); /* success - return total length */
11111         }
11112     }
11113 }
11114
11115 int
11116 http_inc(timo) int timo; {
11117     int x=-1; unsigned char c;             /* The locals. */
11118
11119     if (httpfd == -1) {
11120 #ifdef HTTP_BUFFERING
11121         http_count = 0;
11122         http_bufp = 0;
11123 #endif  /* HTTP_BUFFERING */
11124         debug(F100,"http_inc socket is closed","",0);
11125         return(-2);
11126     }
11127
11128 #ifdef CK_SSL
11129     /*
11130      * In the case of OpenSSL, it is possible that there is still
11131      * data waiting in the SSL session buffers that has not yet
11132      * been read by Kermit.  If this is the case we must process
11133      * it without calling select() because select() will not return
11134      * with an indication that there is data to be read from the
11135      * socket.  If there is no data pending in the SSL session
11136      * buffers then fall through to the select() code and wait for
11137      * some data to arrive.
11138      */
11139     if (tls_http_active_flag) {
11140         int error;
11141
11142         x = SSL_pending(tls_http_con);
11143         if (x < 0) {
11144             debug(F111,"http_inc","SSL_pending error",x);
11145             http_close();
11146             return(-1);
11147         } else if ( x > 0 ) {
11148           ssl_read:
11149             x = SSL_read(tls_http_con, &c, 1);
11150             error = SSL_get_error(tls_http_con,x);
11151             switch (error) {
11152             case SSL_ERROR_NONE:
11153                 debug(F111,"http_inc SSL_ERROR_NONE","x",x);
11154                 if (x > 0) {
11155 #ifdef OS2
11156                     ReleaseTCPIPMutex();
11157 #endif /* OS2 */
11158                     return(c);          /* Return character. */
11159                 } else if (x < 0) {
11160 #ifdef OS2
11161                     ReleaseTCPIPMutex();
11162 #endif /* OS2 */
11163                     return(-1);
11164                 } else {
11165                     http_close();
11166 #ifdef OS2
11167                     ReleaseTCPIPMutex();
11168 #endif /* OS2 */
11169                     return(-2);
11170                 }
11171             case SSL_ERROR_WANT_WRITE:
11172                 debug(F100,"http_inc SSL_ERROR_WANT_WRITE","",0);
11173 #ifdef OS2
11174                 ReleaseTCPIPMutex();
11175 #endif /* OS2 */
11176                 return(-1);
11177             case SSL_ERROR_WANT_READ:
11178                 debug(F100,"http_inc SSL_ERROR_WANT_READ","",0);
11179 #ifdef OS2
11180                 ReleaseTCPIPMutex();
11181 #endif /* OS2 */
11182                 return(-1);
11183             case SSL_ERROR_SYSCALL:
11184                 if ( x == 0 ) { /* EOF */
11185                     http_close();
11186 #ifdef OS2
11187                     ReleaseTCPIPMutex();
11188 #endif /* OS2 */
11189                     return(-2);
11190                 } else {
11191                     int rc = -1;
11192 #ifdef NT
11193                     int gle = GetLastError();
11194                     debug(F111,"http_inc SSL_ERROR_SYSCALL",
11195                            "GetLastError()",gle);
11196                     rc = os2socketerror(gle);
11197                     if (rc == -1)
11198                         rc = -2;
11199                     else if ( rc == -2 )
11200                         rc = -1;
11201 #endif /* NT */
11202 #ifdef OS2
11203                     ReleaseTCPIPMutex();
11204 #endif /* OS2 */
11205                     return(rc);
11206                 }
11207             case SSL_ERROR_WANT_X509_LOOKUP:
11208                 debug(F100,"http_inc SSL_ERROR_WANT_X509_LOOKUP","",0);
11209                 http_close();
11210 #ifdef OS2
11211                 ReleaseTCPIPMutex();
11212 #endif /* OS2 */
11213                 return(-2);
11214             case SSL_ERROR_SSL:
11215                 debug(F100,"http_inc SSL_ERROR_SSL","",0);
11216 #ifdef COMMENT
11217                 http_close();
11218 #endif /* COMMENT */
11219 #ifdef OS2
11220                 ReleaseTCPIPMutex();
11221 #endif /* OS2 */
11222                 return(-2);
11223             case SSL_ERROR_ZERO_RETURN:
11224                 debug(F100,"http_inc SSL_ERROR_ZERO_RETURN","",0);
11225                 http_close();
11226 #ifdef OS2
11227                 ReleaseTCPIPMutex();
11228 #endif /* OS2 */
11229                 return(-2);
11230             default:
11231                 debug(F100,"http_inc SSL_ERROR_?????","",0);
11232                 http_close();
11233 #ifdef OS2
11234                 ReleaseTCPIPMutex();
11235 #endif /* OS2 */
11236                 return(-2);
11237             }
11238         }
11239     }
11240 #endif /* CK_SSL */
11241
11242 #ifdef HTTP_BUFFERING
11243     /* Skip all the select() stuff if we have bytes buffered locally */
11244     if (http_count > 0)
11245       goto getfrombuffer;
11246 #endif  /* HTTP_BUFFERING */
11247
11248     {
11249 #ifdef BSDSELECT
11250         fd_set rfds;
11251         struct timeval tv;
11252         int timeout = timo < 0 ? -timo : 1000 * timo;
11253         debug(F101,"http_inc BSDSELECT","",timo);
11254
11255         for ( ; timeout >= 0; timeout -= (timo ? 100 : 0)) {
11256             int rc;
11257             debug(F111,"http_inc","timeout",timeout);
11258             /* Don't move select() initialization out of the loop. */
11259             FD_ZERO(&rfds);
11260             FD_SET(httpfd, &rfds);
11261             tv.tv_sec  = tv.tv_usec = 0L;
11262             if (timo)
11263                 tv.tv_usec = (long) 100000L;
11264             else
11265                 tv.tv_sec = 30;
11266 #ifdef NT
11267             WSASafeToCancel = 1;
11268 #endif /* NT */
11269             rc = select(FD_SETSIZE,
11270 #ifndef __DECC
11271                          (fd_set *)
11272 #endif /* __DECC */
11273                          &rfds, NULL, NULL, &tv);
11274             if (rc < 0) {
11275                 int s_errno = socket_errno;
11276                 debug(F111,"http_inc","select",rc);
11277                 debug(F111,"http_inc","socket_errno",s_errno);
11278 #ifdef HTTP_BUFFERING
11279                 http_count = 0;
11280                 http_bufp = 0;
11281 #endif  /* HTTP_BUFFERING */
11282                 if (s_errno)
11283                     return(-1);
11284             }
11285             debug(F111,"http_inc","select",rc);
11286 #ifdef NT
11287             WSASafeToCancel = 0;
11288 #endif /* NT */
11289             if (FD_ISSET(httpfd, &rfds)) {
11290                 x = 0;
11291                 break;
11292             } else {
11293                 /* If waiting forever we have no way of knowing if the */
11294                 /* socket closed so try writing a 0-length TCP packet  */
11295                 /* which should force an error if the socket is closed */
11296                 if (!timo) {
11297 #ifdef TCPIPLIB
11298                     if ((rc = socket_write(httpfd,"",0)) < 0) {
11299 #ifdef HTTP_BUFFERING
11300                         http_count = 0;
11301                         http_bufp = 0;
11302 #endif  /* HTTP_BUFFERING */
11303                         int s_errno = socket_errno;
11304                         debug(F101,"http_inc socket_write error","",s_errno);
11305 #ifdef OS2
11306                         if (os2socketerror(s_errno) < 0)
11307                             return(-2);
11308 #endif /* OS2 */
11309                         return(-1); /* Call it an i/o error */
11310                     }
11311 #else /* TCPIPLIB */
11312                     if ((rc = write(httpfd,"",0)) < 0) {
11313 #ifdef HTTP_BUFFERING
11314                         http_count = 0;
11315                         http_bufp = 0;
11316 #endif  /* HTTP_BUFFERING */
11317                         debug(F101,"http_inc socket_write error","",errno);
11318                         return(-1); /* Call it an i/o error */
11319                     }
11320 #endif /* TCPIPLIB */
11321                 }
11322                 continue;
11323             }
11324         }
11325 #ifdef NT
11326         WSASafeToCancel = 0;
11327 #endif /* NT */
11328 #else /* !BSDSELECT */
11329 #ifdef IBMSELECT
11330  /*
11331   Was used by OS/2, currently not used, but might come in handy some day...
11332   ... and it came in handy!  For our TCP/IP layer, it avoids all the fd_set
11333   and timeval stuff since this is the only place where it is used.
11334  */
11335         int socket = httpfd;
11336         int timeout = timo < 0 ? -timo : 1000 * timo;
11337
11338         debug(F101,"http_inc IBMSELECT","",timo);
11339         for ( ; timeout >= 0; timeout -= (timo ? 100 : 0)) {
11340             if (select(&socket, 1, 0, 0, 100L) == 1) {
11341                 x = 0;
11342                 break;
11343             }
11344         }
11345 #else /* !IBMSELECT */
11346         SELECT is required for this code
11347 #endif /* IBMSELECT */
11348 #endif /* BSDSELECT */
11349     }
11350
11351     if (timo && x < 0) {        /* select() timed out */
11352 #ifdef HTTP_BUFFERING
11353         http_count = 0;
11354         http_bufp = 0;
11355 #endif  /* HTTP_BUFFERING */
11356         debug(F100,"http_inc select() timed out","",0);
11357         return(-1); /* Call it an i/o error */
11358     }
11359
11360 #ifdef CK_SSL
11361         if ( tls_http_active_flag ) {
11362             int error;
11363           ssl_read2:
11364             x = SSL_read(tls_http_con, &c, 1);
11365             error = SSL_get_error(tls_http_con,x);
11366             switch (error) {
11367             case SSL_ERROR_NONE:
11368                 debug(F111,"http_inc SSL_ERROR_NONE","x",x);
11369                 if (x > 0) {
11370 #ifdef OS2
11371                     ReleaseTCPIPMutex();
11372 #endif /* OS2 */
11373                     return(c);          /* Return character. */
11374                 } else if (x < 0) {
11375 #ifdef OS2
11376                     ReleaseTCPIPMutex();
11377 #endif /* OS2 */
11378                     return(-1);
11379                 } else {
11380                     http_close();
11381 #ifdef OS2
11382                     ReleaseTCPIPMutex();
11383 #endif /* OS2 */
11384                     return(-2);
11385                 }
11386             case SSL_ERROR_WANT_WRITE:
11387                 debug(F100,"http_inc SSL_ERROR_WANT_WRITE","",0);
11388 #ifdef OS2
11389                 ReleaseTCPIPMutex();
11390 #endif /* OS2 */
11391                 return(-1);
11392             case SSL_ERROR_WANT_READ:
11393                 debug(F100,"http_inc SSL_ERROR_WANT_READ","",0);
11394 #ifdef OS2
11395                 ReleaseTCPIPMutex();
11396 #endif /* OS2 */
11397                 return(-1);
11398             case SSL_ERROR_SYSCALL:
11399                 if ( x == 0 ) { /* EOF */
11400                     http_close();
11401 #ifdef OS2
11402                     ReleaseTCPIPMutex();
11403 #endif /* OS2 */
11404                     return(-2);
11405                 } else {
11406                     int rc = -1;
11407 #ifdef NT
11408                     int gle = GetLastError();
11409                     debug(F111,"http_inc SSL_ERROR_SYSCALL",
11410                            "GetLastError()",gle);
11411                     rc = os2socketerror(gle);
11412                     if (rc == -1)
11413                         rc = -2;
11414                     else if ( rc == -2 )
11415                         rc = -1;
11416 #endif /* NT */
11417 #ifdef OS2
11418                     ReleaseTCPIPMutex();
11419 #endif /* OS2 */
11420                     return(rc);
11421                 }
11422             case SSL_ERROR_WANT_X509_LOOKUP:
11423                 debug(F100,"http_inc SSL_ERROR_WANT_X509_LOOKUP","",0);
11424                 http_close();
11425 #ifdef OS2
11426                 ReleaseTCPIPMutex();
11427 #endif /* OS2 */
11428                 return(-2);
11429             case SSL_ERROR_SSL:
11430                 debug(F100,"http_inc SSL_ERROR_SSL","",0);
11431 #ifdef COMMENT
11432                 http_close();
11433 #endif /* COMMENT */
11434 #ifdef OS2
11435                 ReleaseTCPIPMutex();
11436 #endif /* OS2 */
11437                 return(-2);
11438             case SSL_ERROR_ZERO_RETURN:
11439                 debug(F100,"http_inc SSL_ERROR_ZERO_RETURN","",0);
11440                 http_close();
11441 #ifdef OS2
11442                 ReleaseTCPIPMutex();
11443 #endif /* OS2 */
11444                 return(-2);
11445             default:
11446                 debug(F100,"http_inc SSL_ERROR_?????","",0);
11447                 http_close();
11448 #ifdef OS2
11449                 ReleaseTCPIPMutex();
11450 #endif /* OS2 */
11451                 return(-2);
11452             }
11453         }
11454 #endif /* CK_SSL */
11455
11456 #ifdef HTTP_BUFFERING
11457 /*
11458   Buffering code added by fdc 15 Dec 2005 for non-SSL case only because HTTP
11459   GETs were orders of magnitude too slow due to the single-byte read()s.  The
11460   file-descriptor swapping is pretty gross, but the more elegant solution
11461   (calling a nettchk() like routine with the fd as a parameter) doesn't work,
11462   because nettchk() relies on too many other routines that, like itself, are
11463   hardwired for ttyfd.
11464 */
11465   getfrombuffer:
11466         if (--http_count >= 0) {
11467             c = http_inbuf[http_bufp++];
11468             x = 1;
11469         } else {
11470             int savefd;
11471             savefd = ttyfd;
11472             ttyfd = httpfd;
11473             x = nettchk();
11474             ttyfd = savefd;             
11475             debug(F101,"http_inc nettchk","",x);
11476             if (x > HTTP_INBUFLEN)
11477               x = HTTP_INBUFLEN;
11478 #ifdef TCPIPLIB
11479             x = socket_read(httpfd,http_inbuf,x);
11480 #else  /* Not TCPIPLIB */
11481             x = read(httpfd,http_inbuf,x);
11482 #endif  /* TCPIPLIB */
11483             http_count = 0;
11484             http_bufp = 0;
11485             if (x > 0) {
11486                 c = http_inbuf[http_bufp++];
11487                 http_count = x - 1;
11488             }
11489         }
11490 #else  /* Not HTTP_BUFFERING */
11491 #ifdef TCPIPLIB
11492         x = socket_read(httpfd,&c,1);
11493 #else  /* Not TCPIPLIB */
11494         x = read(httpfd,&c,1);
11495 #endif  /* TCPIPLIB */
11496 #endif  /* HTTP_BUFFERING */
11497
11498         if (x <= 0) {
11499             int s_errno = socket_errno;
11500             debug(F101,"ttbufr socket_read","",x);
11501             debug(F101,"ttbufr socket_errno","",s_errno);
11502 #ifdef OS2
11503             if (x == 0 || os2socketerror(s_errno) < 0) {
11504                 http_close();
11505                 ReleaseTCPIPMutex();
11506                 return(-2);
11507             }
11508             ReleaseTCPIPMutex();
11509             return(-1);
11510 #else /* OS2 */
11511             http_close();                      /* *** *** */
11512             return(-2);
11513 #endif /* OS2 */
11514         }
11515         return(c);
11516 }
11517
11518 void
11519 #ifdef CK_ANSIC
11520 http_set_code_reply(char * msg)
11521 #else
11522 http_set_code_reply(msg)
11523     char * msg;
11524 #endif /* CK_ANSIC */
11525 {
11526     char * p = msg;
11527     char buf[16];
11528     int i=0;
11529
11530     while ( *p != SP && *p != NUL ) {
11531         buf[i] = *p;
11532         p++;
11533         i++;
11534     }
11535
11536     http_code = atoi(buf);
11537
11538     while ( *p == SP )
11539         p++;
11540
11541     ckstrncpy(http_reply_str,p,HTTPBUFLEN);
11542 }
11543
11544 int
11545 #ifdef CK_ANSIC
11546 http_get(char * agent, char ** hdrlist, char * user,
11547          char * pwd, char array, char * local, char * remote,
11548          int stdio)
11549 #else
11550 http_get(agent, hdrlist, user, pwd, array, local, remote, stdio)
11551     char * agent; char ** hdrlist; char * user;
11552     char * pwd; char array; char * local; char * remote;
11553     int stdio;
11554 #endif /* CK_ANSIC */
11555 {
11556     char * request = NULL;
11557     int    i, j, len = 0, hdcnt = 0, rc = 0;
11558     int    ch;
11559     int    http_fnd = 0;
11560     char   buf[HTTPBUFLEN], *p;
11561     int    nullline;
11562 #ifdef OS2
11563     struct utimbuf u_t;
11564 #else /* OS2 */
11565 #ifdef SYSUTIMEH
11566     struct utimbuf u_t;
11567 #else
11568     struct utimbuf {
11569         time_t atime;
11570         time_t mtime;
11571     } u_t;
11572 #endif /* SYSUTIMH */
11573 #endif /* OS2 */
11574     time_t mod_t = 0;
11575     time_t srv_t = 0;
11576     time_t local_t = 0;
11577     char passwd[64];
11578     char b64in[128];
11579     char b64out[256];
11580     char * headers[HTTPHEADCNT];
11581     int closecon = 0;
11582     int chunked = 0;
11583     int zfile = 0;
11584     int first = 1;
11585
11586 #ifdef DEBUG
11587     if (deblog) {
11588         debug(F101,"http_get httpfd","",httpfd);
11589         debug(F110,"http_agent",agent,0);
11590         debug(F110,"http_user",user,0);
11591         debug(F110,"http_local",local,0);
11592         debug(F110,"http_remote",remote,0);
11593     }
11594 #endif /* DEBUG */
11595     if (!remote) remote = "";
11596
11597     if (httpfd == -1)
11598       return(-1);
11599
11600     if (array) {
11601         for (i = 0; i < HTTPHEADCNT; i++)
11602           headers[i] = NULL;
11603     }
11604     len = 8;                            /* GET */
11605     len += strlen(HTTP_VERSION);
11606     len += strlen(remote);
11607     len += 16;
11608
11609     if (hdrlist) {
11610         for (i = 0; hdrlist[i]; i++)
11611             len += strlen(hdrlist[i]) + 2;
11612     }
11613     len += (int) strlen(http_host_port) + 8;
11614
11615     if (agent)
11616       len += 13 + strlen(agent);
11617     if (user) {
11618         if (!pwd) {
11619             readpass("Password: ",passwd,64);
11620             pwd = passwd;
11621         }
11622         ckmakmsg(b64in,sizeof(b64in),user,":",pwd,NULL);
11623         j = b8tob64(b64in,strlen(b64in),b64out,256);
11624         memset(pwd,0,strlen(pwd));      /* NOT PORTABLE */
11625         if (j < 0)
11626           return(-1);
11627         b64out[j] = '\0';
11628         len += j + 24;
11629     }
11630 #ifdef HTTP_CLOSE
11631     len += 19;                          /* Connection: close */
11632 #endif
11633     len += 3;                           /* blank line + null */
11634
11635     request = malloc(len);
11636     if (!request)
11637       return(-1);
11638
11639     sprintf(request,"GET %s %s\r\n",remote,HTTP_VERSION);       /* safe */
11640     ckstrncat(request,"Host: ", len);
11641     ckstrncat(request,http_host_port, len);
11642     ckstrncat(request,"\r\n",len);
11643     if (agent) {
11644         ckstrncat(request,"User-agent: ",len);
11645         ckstrncat(request,agent,len);
11646         ckstrncat(request,"\r\n",len);
11647     }
11648     if (user) {
11649         ckstrncat(request,"Authorization: Basic ",len);
11650         ckstrncat(request,b64out,len);
11651         ckstrncat(request,"\r\n",len);
11652     }
11653     if ( hdrlist ) {
11654         for (i = 0; hdrlist[i]; i++) {
11655             ckstrncat(request,hdrlist[i],len);
11656             ckstrncat(request,"\r\n",len);
11657         }
11658     }
11659 #ifdef HTTP_CLOSE
11660     ckstrncat(request,"Connection: close\r\n",len);
11661 #endif
11662     ckstrncat(request,"\r\n",len);
11663
11664   getreq:
11665     if (http_tol((CHAR *)request,strlen(request)) < 0)
11666     {
11667         http_close();
11668         if ( first ) {
11669             first--;
11670             http_reopen();
11671             goto getreq;
11672         }
11673         rc = -1;
11674         goto getexit;
11675     }
11676
11677     /* Process the headers */
11678     local_t = time(NULL);
11679     nullline = 0;
11680     i = 0;
11681     len = -1;
11682     while (!nullline && (ch = http_inc(0)) >= 0 && i < HTTPBUFLEN) {
11683         buf[i] = ch;
11684         if ( buf[i] == 10 ) { /* found end of line */
11685             if (i > 0 && buf[i-1] == 13)
11686               i--;
11687             if (i < 1)
11688               nullline = 1;
11689             buf[i] = '\0';
11690             if (array && !nullline && hdcnt < HTTPHEADCNT)
11691               makestr(&headers[hdcnt++],buf);
11692             if (!ckstrcmp(buf,"HTTP",4,0)) {
11693                 http_fnd = 1;
11694                 j = ckindex(" ",buf,0,0,0);
11695                 p = &buf[j];
11696                 while ( isspace(*p) )
11697                   p++;
11698                 switch ( p[0] ) {
11699                   case '1':             /* Informational message */
11700                     break;
11701                   case '2':             /* Success */
11702                     break;
11703                   case '3':             /* Redirection */
11704                   case '4':             /* Client failure */
11705                   case '5':             /* Server failure */
11706                   default:              /* Unknown */
11707                     if (!quiet)
11708                       printf("Failure: Server reports %s\n",p);
11709                     rc = -1;
11710                     local = NULL;
11711                 }
11712                 http_set_code_reply(p);
11713 #ifdef CMDATE2TM
11714             } else if (!ckstrcmp(buf,"Last-Modified",13,0)) {
11715                 mod_t = http_date(&buf[15]);
11716             } else if (!ckstrcmp(buf,"Date",4,0)) {
11717                 srv_t = http_date(&buf[4]);
11718 #endif /* CMDATE2TM */
11719             } else if (!ckstrcmp(buf,"Connection:",11,0)) {
11720                 if ( ckindex("close",buf,11,0,0) != 0 )
11721                     closecon = 1;
11722             } else if (!ckstrcmp(buf,"Content-Length:",15,0)) {
11723                 len = atoi(&buf[16]);
11724             } else if (!ckstrcmp(buf,"Transfer-Encoding:",18,0)) {
11725                 if ( ckindex("chunked",buf,18,0,0) != 0 )
11726                     chunked = 1;
11727                 debug(F101,"http_get chunked","",chunked);
11728             }
11729             i = 0;
11730         } else {
11731             i++;
11732         }
11733     }
11734     if (ch < 0 && first) {
11735         first--;
11736         http_close();
11737         http_reopen();
11738         goto getreq;
11739     }
11740     if (http_fnd == 0) {
11741         rc = -1;
11742         closecon = 1;
11743         goto getexit;
11744     }
11745
11746     /* Now we have the contents of the file */
11747     if ( local && local[0] ) {
11748         if (zopeno(ZOFILE,local,NULL,NULL))
11749             zfile = 1;
11750         else
11751             rc = -1;
11752     }
11753
11754     if ( chunked ) {
11755         while ((len = http_get_chunk_len()) > 0) {
11756             while (len && (ch = http_inc(0)) >= 0) {
11757                 len--;
11758                 if ( zfile )
11759                     zchout(ZOFILE,(CHAR)ch);
11760                 if ( stdio )
11761                     conoc((CHAR)ch);
11762             }
11763             if ((ch = http_inc(0)) != CR)
11764                 break;
11765             if ((ch = http_inc(0)) != LF)
11766                 break;
11767         }
11768     } else {
11769         while (len && (ch = http_inc(0)) >= 0) {
11770             len--;
11771             if ( zfile )
11772                 zchout(ZOFILE,(CHAR)ch);
11773             if ( stdio )
11774                 conoc((CHAR)ch);
11775         }
11776     }
11777
11778     if ( zfile )
11779         zclose(ZOFILE);
11780
11781     if ( chunked ) {            /* Parse Trailing Headers */
11782         nullline = 0;
11783         while (!nullline && (ch = http_inc(0)) >= 0 && i < HTTPBUFLEN) {
11784             buf[i] = ch;
11785             if ( buf[i] == 10 ) { /* found end of line */
11786                 if (i > 0 && buf[i-1] == 13)
11787                   i--;
11788                 if (i < 1)
11789                   nullline = 1;
11790                 buf[i] = '\0';
11791                 if (array && !nullline && hdcnt < HTTPHEADCNT)
11792                     makestr(&headers[hdcnt++],buf);
11793 #ifdef CMDATE2TM
11794                 if (!ckstrcmp(buf,"Last-Modified",13,0)) {
11795                     mod_t = http_date(&buf[15]);
11796                 } else if (!ckstrcmp(buf,"Date",4,0)) {
11797                     srv_t = http_date(&buf[4]);
11798                 }
11799 #endif /* CMDATE2TM */
11800                 else if (!ckstrcmp(buf,"Connection:",11,0)) {
11801                     if ( ckindex("close",buf,11,0,0) != 0 )
11802                         closecon = 1;
11803                 }
11804                 i = 0;
11805             } else {
11806                 i++;
11807             }
11808         }
11809     }
11810
11811     if ( zfile ) {              /* Set timestamp */
11812 #ifndef NOSETTIME
11813 #ifdef OS2
11814         u_t.actime = srv_t ? srv_t : local_t;
11815         u_t.modtime = mod_t ? mod_t : local_t;
11816 #else /* OS2 */
11817 #ifdef SYSUTIMEH
11818         u_t.actime = srv_t ? srv_t : local_t;
11819         u_t.modtime = mod_t ? mod_t : local_t;
11820 #else
11821 #ifdef BSD44
11822         u_t[0].tv_sec = srv_t ? srv_t : local_t;
11823         u_t[1].tv_sec = mod_t ? mod_t : local_t;
11824 #else
11825         u_t.mtime = srv_t ? srv_t : local_t;
11826         u_t.atime = mod_t ? mod_t : local_t;
11827 #endif /* BSD44 */
11828 #endif /* SYSUTIMEH */
11829 #endif /* OS2 */
11830             utime(local,&u_t);
11831 #endif /* NOSETTIME */
11832     }
11833
11834   getexit:
11835     if (array)
11836       http_mkarray(headers,hdcnt,array);
11837
11838     if ( closecon )
11839         http_close();
11840     free(request);
11841     for (i = 0; i < hdcnt; i++) {
11842         if (headers[i])
11843           free(headers[i]);
11844     }
11845     return(rc);
11846 }
11847
11848 int
11849 #ifdef CK_ANSIC
11850 http_head(char * agent, char ** hdrlist, char * user,
11851           char * pwd, char array, char * local, char * remote,
11852           int stdio)
11853 #else
11854 http_head(agent, hdrlist, user, pwd, array, local, remote, stdio)
11855     char * agent; char ** hdrlist; char * user;
11856     char * pwd; char array; char * local; char * remote;
11857     int stdio;
11858 #endif /* CK_ANSIC */
11859 {
11860     char * request = NULL;
11861     int    i, j, len = 0, hdcnt = 0, rc = 0;
11862     int    ch;
11863     int    http_fnd = 0;
11864     char   buf[HTTPBUFLEN], *p;
11865     int    nullline;
11866     time_t mod_t;
11867     time_t srv_t;
11868     time_t local_t;
11869     char passwd[64];
11870     char b64in[128];
11871     char b64out[256];
11872     char * headers[HTTPHEADCNT];
11873     int  closecon = 0;
11874     int  first = 1;
11875
11876     if (httpfd == -1)
11877       return(-1);
11878
11879     if (array) {
11880         for (i = 0; i < HTTPHEADCNT; i++)
11881           headers[i] = NULL;
11882     }
11883     len = 9;                            /* HEAD */
11884     len += strlen(HTTP_VERSION);
11885     len += strlen(remote);
11886     len += 16;
11887
11888     if ( hdrlist ) {
11889         for (i = 0; hdrlist[i]; i++)
11890             len += strlen(hdrlist[i]) + 2;
11891     }
11892     len += strlen(http_host_port) + 8;
11893
11894     if (agent)
11895       len += 13 + strlen(agent);
11896     if (user) {
11897         if (!pwd) {
11898             readpass("Password: ",passwd,64);
11899             pwd = passwd;
11900         }
11901         ckmakmsg(b64in,sizeof(b64in),user,":",pwd,NULL);
11902         j = b8tob64(b64in,strlen(b64in),b64out,256);
11903         memset(pwd,0,strlen(pwd));      /* NOT PORTABLE */
11904         if (j < 0)
11905           return(-1);
11906         b64out[j] = '\0';
11907         len += j + 24;
11908     }
11909 #ifdef HTTP_CLOSE
11910     len += 19;                          /* Connection: close */
11911 #endif
11912     len += 3;                           /* blank line + null */
11913
11914     request = (char *)malloc(len);
11915     if (!request)
11916       return(-1);
11917
11918     sprintf(request,"HEAD %s %s\r\n",remote,HTTP_VERSION);
11919     ckstrncat(request,"Host: ", len);
11920     ckstrncat(request,http_host_port, len);
11921     ckstrncat(request,"\r\n",len);
11922     if (agent) {
11923         ckstrncat(request,"User-agent: ",len);
11924         ckstrncat(request,agent,len);
11925         ckstrncat(request,"\r\n",len);
11926     }
11927     if (user) {
11928         ckstrncat(request,"Authorization: Basic ",len);
11929         ckstrncat(request,b64out,len);
11930         ckstrncat(request,"\r\n",len);
11931     }
11932     if ( hdrlist ) {
11933         for (i = 0; hdrlist[i]; i++) {
11934             ckstrncat(request,hdrlist[i],len);
11935             ckstrncat(request,"\r\n",len);
11936         }
11937     }
11938 #ifdef HTTP_CLOSE
11939     ckstrncat(request,"Connection: close\r\n",len);
11940 #endif
11941     ckstrncat(request,"\r\n",len);
11942
11943     if ( local && local[0] ) {
11944         if (!zopeno(ZOFILE,local,NULL,NULL)) {
11945             free(request);
11946             return(-1);
11947         }
11948     }
11949
11950   headreq:
11951     if (http_tol((CHAR *)request,strlen(request)) < 0)
11952     {
11953         http_close();
11954         if ( first ) {
11955             first--;
11956             http_reopen();
11957             goto headreq;
11958         }
11959         rc = -1;
11960         goto headexit;
11961     }
11962
11963     /* Process the headers */
11964
11965     local_t = time(NULL);
11966     nullline = 0;
11967     i = 0;
11968     while (!nullline && (ch = http_inc(0)) >= 0 && i < HTTPBUFLEN) {
11969         buf[i] = ch;
11970         if (buf[i] == 10) {             /* found end of line */
11971             if (i > 0 && buf[i-1] == 13)
11972               i--;
11973             if (i < 1)
11974               nullline = 1;
11975             buf[i] = '\0';
11976             if (array && !nullline && hdcnt < HTTPHEADCNT)
11977               makestr(&headers[hdcnt++],buf);
11978             if (!ckstrcmp(buf,"HTTP",4,0)) {
11979                 http_fnd = 1;
11980                 j = ckindex(" ",buf,0,0,0);
11981                 p = &buf[j];
11982                 while (isspace(*p))
11983                   p++;
11984                 switch (p[0]) {
11985                   case '1':             /* Informational message */
11986                     break;
11987                   case '2':             /* Success */
11988                     break;
11989                   case '3':             /* Redirection */
11990                   case '4':             /* Client failure */
11991                   case '5':             /* Server failure */
11992                   default:              /* Unknown */
11993                     if (!quiet)
11994                       printf("Failure: Server reports %s\n",p);
11995                     rc = -1;
11996                 }
11997                 http_set_code_reply(p);
11998             } else {
11999                 if (!ckstrcmp(buf,"Connection:",11,0)) {
12000                     if ( ckindex("close",buf,11,0,0) != 0 )
12001                         closecon = 1;
12002                 }
12003                 if ( local && local[0] ) {
12004                     zsout(ZOFILE,buf);
12005                     zsout(ZOFILE,"\r\n");
12006                 }
12007                 if (stdio)
12008                     printf("%s\r\n",buf);
12009             }
12010             i = 0;
12011         } else {
12012             i++;
12013         }
12014     }
12015     if (ch < 0 && first) {
12016         first--;
12017         http_close();
12018         http_reopen();
12019         goto headreq;
12020     }
12021     if ( http_fnd == 0 )
12022         rc = -1;
12023
12024     if (array)
12025       http_mkarray(headers,hdcnt,array);
12026
12027   headexit:
12028     if ( local && local[0] )
12029         zclose(ZOFILE);
12030     if (closecon)
12031         http_close();
12032     free(request);
12033     for (i = 0; i < hdcnt; i++) {
12034         if (headers[i])
12035           free(headers[i]);
12036     }
12037     return(rc);
12038 }
12039
12040 int
12041 #ifdef CK_ANSIC
12042 http_index(char * agent, char ** hdrlist, char * user, char * pwd,
12043              char array, char * local, char * remote, int stdio)
12044 #else
12045 http_index(agent, hdrlist, user, pwd, array, local, remote, stdio)
12046     char * agent; char ** hdrlist; char * user; char * pwd;
12047     char array; char * local; char * remote; int stdio;
12048 #endif /* CK_ANSIC */
12049 {
12050     char * request = NULL;
12051     int    i, j, len = 0, hdcnt = 0, rc = 0;
12052     int    ch;
12053     int    http_fnd = 0;
12054     char   buf[HTTPBUFLEN], *p;
12055     int    nullline;
12056     time_t mod_t;
12057     time_t srv_t;
12058     time_t local_t;
12059     char passwd[64];
12060     char b64in[128];
12061     char b64out[256];
12062     char * headers[HTTPHEADCNT];
12063     int  closecon = 0;
12064     int  chunked = 0;
12065     int  zfile = 0;
12066     int  first = 1;
12067
12068     if (httpfd == -1)
12069       return(-1);
12070
12071     if (array) {
12072         for (i = 0; i < HTTPHEADCNT; i++)
12073           headers[i] = NULL;
12074     }
12075     len = 10;                            /* INDEX */
12076     len += strlen(HTTP_VERSION);
12077     len += strlen(remote);
12078     len += 16;
12079
12080     if ( hdrlist ) {
12081         for (i = 0; hdrlist[i]; i++)
12082             len += strlen(hdrlist[i]) + 2;
12083     }
12084     len += strlen(http_host_port) + 8;
12085
12086     if (agent)
12087         len += 13 + strlen(agent);
12088     if (user) {
12089         if (!pwd) {
12090             readpass("Password: ",passwd,64);
12091             pwd = passwd;
12092         }
12093         ckmakmsg(b64in,sizeof(b64in),user,":",pwd,NULL);
12094         j = b8tob64(b64in,strlen(b64in),b64out,256);
12095         memset(pwd,0,strlen(pwd));
12096         if (j < 0)
12097           return(-1);
12098         b64out[j] = '\0';
12099         len += j + 24;
12100     }
12101 #ifdef HTTP_CLOSE
12102     len += 19;                          /* Connection: close */
12103 #endif
12104     len += 3;                           /* blank line + null */
12105
12106     request = malloc(len);
12107     if (!request)
12108       return(-1);
12109
12110     sprintf(request,"INDEX %s\r\n",HTTP_VERSION);
12111     ckstrncat(request,"Host: ", len);
12112     ckstrncat(request,http_host_port, len);
12113     ckstrncat(request,"\r\n",len);
12114     if (agent) {
12115         ckstrncat(request,"User-agent: ",len);
12116         ckstrncat(request,agent,len);
12117         ckstrncat(request,"\r\n",len);
12118     }
12119     if (user) {
12120         ckstrncat(request,"Authorization: Basic ",len);
12121         ckstrncat(request,b64out,len);
12122         ckstrncat(request,"\r\n",len);
12123     }
12124     if ( hdrlist ) {
12125         for (i = 0; hdrlist[i]; i++) {
12126             ckstrncat(request,hdrlist[i],len);
12127             ckstrncat(request,"\r\n",len);
12128         }
12129     }
12130 #ifdef HTTP_CLOSE
12131     ckstrncat(request,"Connection: close\r\n",len);
12132 #endif
12133     ckstrncat(request,"\r\n",len);
12134   indexreq:
12135     if (http_tol((CHAR *)request,strlen(request)) < 0)
12136     {
12137         http_close();
12138         if ( first ) {
12139             first--;
12140             http_reopen();
12141             goto indexreq;
12142         }
12143         rc = -1;
12144         goto indexexit;
12145     }
12146
12147     /* Process the headers */
12148     local_t = time(NULL);
12149     nullline = 0;
12150     i = 0;
12151     len = -1;
12152     while (!nullline && (ch = http_inc(0)) >= 0 && i < HTTPBUFLEN) {
12153         buf[i] = ch;
12154         if (buf[i] == 10) {             /* found end of line */
12155             if (i > 0 && buf[i-1] == 13)
12156               i--;
12157             if (i < 1)
12158               nullline = 1;
12159             buf[i] = '\0';
12160             if (array && !nullline && hdcnt < HTTPHEADCNT)
12161               makestr(&headers[hdcnt++],buf);
12162             if (!ckstrcmp(buf,"HTTP",4,0)) {
12163                 http_fnd = 1;
12164                 j = ckindex(" ",buf,0,0,0);
12165                 p = &buf[j];
12166                 while (isspace(*p))
12167                   p++;
12168                 switch ( p[0] ) {
12169                   case '1':             /* Informational message */
12170                     break;
12171                   case '2':             /* Success */
12172                     break;
12173                   case '3':             /* Redirection */
12174                   case '4':             /* Client failure */
12175                   case '5':             /* Server failure */
12176                   default:              /* Unknown */
12177                     if (!quiet)
12178                       printf("Failure: Server reports %s\n",p);
12179                     rc = -1;
12180                 }
12181                 http_set_code_reply(p);
12182             } else if ( !nullline ) {
12183                 if (!ckstrcmp(buf,"Connection:",11,0)) {
12184                     if ( ckindex("close",buf,11,0,0) != 0 )
12185                         closecon = 1;
12186                 } else if (!ckstrcmp(buf,"Content-Length:",15,0)) {
12187                     len = atoi(&buf[16]);
12188                 } else if (!ckstrcmp(buf,"Transfer-Encoding:",18,0)) {
12189                     if ( ckindex("chunked",buf,18,0,0) != 0 )
12190                         chunked = 1;
12191                     debug(F101,"http_index chunked","",chunked);
12192                 }
12193                 printf("%s\n",buf);
12194             }
12195             i = 0;
12196         } else {
12197             i++;
12198         }
12199     }
12200
12201     if (ch < 0 && first) {
12202         first--;
12203         http_close();
12204         http_reopen();
12205         goto indexreq;
12206     }
12207     if ( http_fnd == 0 ) {
12208         rc = -1;
12209         closecon = 1;
12210         goto indexexit;
12211     }
12212
12213     /* Now we have the contents of the file */
12214     if ( local && local[0] ) {
12215         if (zopeno(ZOFILE,local,NULL,NULL))
12216             zfile = 1;
12217         else
12218             rc = -1;
12219     }
12220
12221     if ( chunked ) {
12222         while ((len = http_get_chunk_len()) > 0) {
12223             while (len && (ch = http_inc(0)) >= 0) {
12224                 len--;
12225                 if ( zfile )
12226                     zchout(ZOFILE,(CHAR)ch);
12227                 if ( stdio )
12228                     conoc((CHAR)ch);
12229             }
12230             if ((ch = http_inc(0)) != CR)
12231                 break;
12232             if ((ch = http_inc(0)) != LF)
12233                 break;
12234         }
12235     } else {
12236         while (len && (ch = http_inc(0)) >= 0) {
12237             len--;
12238             if ( zfile )
12239                 zchout(ZOFILE,(CHAR)ch);
12240             if ( stdio )
12241                 conoc((CHAR)ch);
12242         }
12243     }
12244
12245     if ( zfile )
12246         zclose(ZOFILE);
12247
12248     if ( chunked ) {            /* Parse Trailing Headers */
12249         nullline = 0;
12250         while (!nullline && (ch = http_inc(0)) >= 0 && i < HTTPBUFLEN) {
12251             buf[i] = ch;
12252             if ( buf[i] == 10 ) { /* found end of line */
12253                 if (i > 0 && buf[i-1] == 13)
12254                   i--;
12255                 if (i < 1)
12256                   nullline = 1;
12257                 buf[i] = '\0';
12258                 if (array && !nullline && hdcnt < HTTPHEADCNT)
12259                     makestr(&headers[hdcnt++],buf);
12260                 if (!ckstrcmp(buf,"Connection:",11,0)) {
12261                     if ( ckindex("close",buf,11,0,0) != 0 )
12262                         closecon = 1;
12263                 }
12264                 i = 0;
12265             } else {
12266                 i++;
12267             }
12268         }
12269     }
12270     rc = 0;
12271
12272   indexexit:
12273     if (array)
12274       http_mkarray(headers,hdcnt,array);
12275
12276     if (closecon)
12277         http_close();
12278     free(request);
12279     for (i = 0; i < hdcnt; i++) {
12280         if (headers[i])
12281           free(headers[i]);
12282     }
12283     return(rc);
12284 }
12285
12286 int
12287 #ifdef CK_ANSIC
12288 http_put(char * agent, char ** hdrlist, char * mime, char * user,
12289          char * pwd, char array, char * local, char * remote,
12290          char * dest, int stdio)
12291 #else
12292 http_put(agent, hdrlist, mime, user, pwd, array, local, remote, dest, stdio)
12293     char * agent; char ** hdrlist; char * mime; char * user;
12294     char * pwd; char array; char * local; char * remote; char * dest;
12295     int stdio;
12296 #endif /* CK_ANSIC */
12297 {
12298     char * request=NULL;
12299     int    i, j, len = 0, hdcnt = 0, rc = 0;
12300     int    ch;
12301     int    http_fnd = 0;
12302     char   buf[HTTPBUFLEN], *p;
12303     int    nullline;
12304     time_t mod_t;
12305     time_t srv_t;
12306     time_t local_t;
12307     char passwd[64];
12308     char b64in[128];
12309     char b64out[256];
12310     int  filelen;
12311     char * headers[HTTPHEADCNT];
12312     int  closecon = 0;
12313     int  chunked = 0;
12314     int  first = 1;
12315     int  zfile = 0;
12316
12317     if (httpfd == -1)
12318       return(-1);
12319     if (!mime) mime = "";
12320     if (!remote) remote = "";
12321     if (!local) local = "";
12322     if (!*local) return(-1);
12323
12324     if (array) {
12325         for (i = 0; i < HTTPHEADCNT; i++)
12326           headers[i] = NULL;
12327     }
12328     filelen = zchki(local);
12329     if (filelen < 0)
12330       return(-1);
12331
12332     /* Compute length of request header */
12333     len = 8;                            /* PUT */
12334     len += strlen(HTTP_VERSION);
12335     len += strlen(remote);
12336     len += 16;
12337
12338     if ( hdrlist ) {
12339         for (i = 0; hdrlist[i]; i++)
12340             len += strlen(hdrlist[i]) + 2;
12341     }
12342     len += strlen(http_host_port) + 8;
12343
12344     if (agent)
12345       len += 13 + strlen(agent);
12346     if (user) {
12347         if (!pwd) {
12348             readpass("Password: ",passwd,64);
12349             pwd = passwd;
12350         }
12351         ckmakmsg(b64in,sizeof(b64in),user,":",pwd,NULL);
12352         j = b8tob64(b64in,strlen(b64in),b64out,256);
12353         memset(pwd,0,strlen(pwd));
12354         if (j < 0)
12355           return(-1);
12356         b64out[j] = '\0';
12357         len += j + 24;
12358     }
12359     len += 16 + strlen(mime);           /* Content-type: */
12360     len += 32;                          /* Content-length: */
12361     len += 32;                          /* Date: */
12362 #ifdef HTTP_CLOSE
12363     len += 19;                          /* Connection: close */
12364 #endif
12365     len += 3;                           /* blank line + null */
12366
12367     request = malloc(len);
12368     if (!request)
12369       return(-1);
12370
12371     sprintf(request,"PUT %s %s\r\n",remote,HTTP_VERSION);
12372     ckstrncat(request,"Date: ",len);
12373 #ifdef CMDATE2TM
12374     ckstrncat(request,http_now(),len);
12375 #else
12376     ckstrncat(request,...,len);
12377 #endif /* CMDATE2TM */
12378     ckstrncat(request,"\r\n",len);
12379     ckstrncat(request,"Host: ", len);
12380     ckstrncat(request,http_host_port, len);
12381     ckstrncat(request,"\r\n",len);
12382     if (agent) {
12383         ckstrncat(request,"User-agent: ",len);
12384         ckstrncat(request,agent,len);
12385         ckstrncat(request,"\r\n",len);
12386     }
12387     if (user) {
12388         ckstrncat(request,"Authorization: Basic ",len);
12389         ckstrncat(request,b64out,len);
12390         ckstrncat(request,"\r\n",len);
12391     }
12392     if ( hdrlist ) {
12393         for (i = 0; hdrlist[i]; i++) {
12394             ckstrncat(request,hdrlist[i],len);
12395             ckstrncat(request,"\r\n",len);
12396         }
12397     }
12398     ckstrncat(request,"Content-type: ",len);
12399     ckstrncat(request,mime,len);
12400     ckstrncat(request,"\r\n",len);
12401     sprintf(buf,"Content-length: %d\r\n",filelen); /* safe */
12402     ckstrncat(request,buf,len);
12403 #ifdef HTTP_CLOSE
12404     ckstrncat(request,"Connection: close\r\n",len);
12405 #endif
12406     ckstrncat(request,"\r\n",len);
12407
12408     /* Now we have the contents of the file */
12409     if (zopeni(ZIFILE,local)) {
12410
12411       putreq:                           /* Send request */
12412         if (http_tol((CHAR *)request,strlen(request)) <= 0) {
12413             http_close();
12414             if ( first ) {
12415                 first--;
12416                 http_reopen();
12417                 goto putreq;
12418             }
12419             zclose(ZIFILE);
12420             rc = -1;
12421             goto putexit;
12422         }
12423         /* Request headers have been sent */
12424
12425         i = 0;
12426         while (zchin(ZIFILE,&ch) == 0) {
12427             buf[i++] = ch;
12428             if (i == HTTPBUFLEN) {
12429                 if (http_tol((CHAR *)buf,HTTPBUFLEN) <= 0) {
12430                     http_close();
12431                     if ( first ) {
12432                         first--;
12433                         http_reopen();
12434                         goto putreq;
12435                     }
12436                 }
12437                 i = 0;
12438             }
12439         }
12440         if (i > 0) {
12441             if (http_tol((CHAR *)buf,i) < 0) {
12442                 http_close();
12443                 if ( first ) {
12444                     first--;
12445                     http_reopen();
12446                     goto putreq;
12447                 }
12448             }
12449         }
12450         zclose(ZIFILE);
12451
12452         /* Process the response headers */
12453         local_t = time(NULL);
12454         nullline = 0;
12455         i = 0;
12456         len = -1;
12457         while (!nullline && (ch = http_inc(0)) >= 0 && i < HTTPBUFLEN) {
12458             buf[i] = ch;
12459             if (buf[i] == 10) {         /* found end of line */
12460                 if (i > 0 && buf[i-1] == 13)
12461                   i--;
12462                 if (i < 1)
12463                   nullline = 1;
12464                 buf[i] = '\0';
12465                 if (array && !nullline && hdcnt < HTTPHEADCNT)
12466                   makestr(&headers[hdcnt++],buf);
12467                 if (!ckstrcmp(buf,"HTTP",4,0)) {
12468                     http_fnd = 1;
12469                     j = ckindex(" ",buf,0,0,0);
12470                     p = &buf[j];
12471                     while (isspace(*p))
12472                       p++;
12473                     switch (p[0]) {
12474                       case '1':         /* Informational message */
12475                         break;
12476                       case '2':         /* Success */
12477                         break;
12478                       case '3':         /* Redirection */
12479                       case '4':         /* Client failure */
12480                       case '5':         /* Server failure */
12481                       default:          /* Unknown */
12482                         if (!quiet)
12483                           printf("Failure: Server reports %s\n",p);
12484                         rc = -1;
12485                     }
12486                     http_set_code_reply(p);
12487                 } else {
12488                     if (!ckstrcmp(buf,"Connection:",11,0)) {
12489                         if ( ckindex("close",buf,11,0,0) != 0 )
12490                             closecon = 1;
12491                     } else if (!ckstrcmp(buf,"Content-Length:",15,0)) {
12492                         len = atoi(&buf[16]);
12493                     } else if (!ckstrcmp(buf,"Transfer-Encoding:",18,0)) {
12494                         if ( ckindex("chunked",buf,18,0,0) != 0 )
12495                             chunked = 1;
12496                         debug(F101,"http_put chunked","",chunked);
12497                     }
12498                     if ( stdio )
12499                         printf("%s\n",buf);
12500                 }
12501                 i = 0;
12502             } else {
12503                 i++;
12504             }
12505         }
12506         if (ch < 0 && first) {
12507             first--;
12508             http_close();
12509             http_reopen();
12510             goto putreq;
12511         }
12512         if ( http_fnd == 0 ) {
12513             closecon = 1;
12514             rc = -1;
12515             goto putexit;
12516         }
12517
12518         /* Any response data? */
12519         if ( dest && dest[0] ) {
12520             if (zopeno(ZOFILE,dest,NULL,NULL))
12521                 zfile = 1;
12522             else
12523                 rc = -1;
12524         }
12525
12526         if ( chunked ) {
12527             while ((len = http_get_chunk_len()) > 0) {
12528                 while (len && (ch = http_inc(0)) >= 0) {
12529                     len--;
12530                     if ( zfile )
12531                         zchout(ZOFILE,(CHAR)ch);
12532                     if ( stdio )
12533                         conoc((CHAR)ch);
12534                 }
12535                 if ((ch = http_inc(0)) != CR)
12536                     break;
12537                 if ((ch = http_inc(0)) != LF)
12538                     break;
12539             }
12540         } else {
12541             while (len && (ch = http_inc(0)) >= 0) {
12542                 len--;
12543                 if ( zfile )
12544                     zchout(ZOFILE,(CHAR)ch);
12545                 if ( stdio )
12546                     conoc((CHAR)ch);
12547             }
12548         }
12549
12550         if ( zfile )
12551             zclose(ZOFILE);
12552
12553         if ( chunked ) {            /* Parse Trailing Headers */
12554             nullline = 0;
12555             while (!nullline && (ch = http_inc(0)) >= 0 && i < HTTPBUFLEN) {
12556                 buf[i] = ch;
12557                 if ( buf[i] == 10 ) { /* found end of line */
12558                     if (i > 0 && buf[i-1] == 13)
12559                       i--;
12560                     if (i < 1)
12561                       nullline = 1;
12562                     buf[i] = '\0';
12563                     if (array && !nullline && hdcnt < HTTPHEADCNT)
12564                         makestr(&headers[hdcnt++],buf);
12565                     if (!ckstrcmp(buf,"Connection:",11,0)) {
12566                         if ( ckindex("close",buf,11,0,0) != 0 )
12567                             closecon = 1;
12568                     }
12569                     i = 0;
12570                 } else {
12571                     i++;
12572                 }
12573             }
12574         }
12575     } else {
12576         rc = -1;
12577     }
12578
12579   putexit:
12580     if ( array )
12581         http_mkarray(headers,hdcnt,array);
12582
12583     if (closecon)
12584         http_close();
12585     free(request);
12586     for (i = 0; i < hdcnt; i++) {
12587         if (headers[i])
12588           free(headers[i]);
12589     }
12590     return(rc);
12591 }
12592
12593 int
12594 #ifdef CK_ANSIC
12595 http_delete(char * agent, char ** hdrlist, char * user,
12596           char * pwd, char array, char * remote)
12597 #else
12598 http_delete(agent, hdrlist, user, pwd, array, remote)
12599     char * agent; char ** hdrlist; char * user;
12600     char * pwd; char array; char * remote;
12601 #endif /* CK_ANSIC */
12602 {
12603     char * request=NULL;
12604     int    i, j, len = 0, hdcnt = 0, rc = 0;
12605     int    ch;
12606     int    http_fnd = 0;
12607     char   buf[HTTPBUFLEN], *p;
12608     int    nullline;
12609     time_t mod_t;
12610     time_t srv_t;
12611     time_t local_t;
12612     char passwd[64];
12613     char b64in[128];
12614     char b64out[256];
12615     char * headers[HTTPHEADCNT];
12616     int  closecon = 0;
12617     int  chunked = 0;
12618     int  first = 1;
12619
12620     if (httpfd == -1)
12621       return(-1);
12622
12623     if (array) {
12624         for (i = 0; i < HTTPHEADCNT; i++)
12625           headers[i] = NULL;
12626     }
12627
12628     /* Compute length of request header */
12629     len = 11;                            /* DELETE */
12630     len += strlen(HTTP_VERSION);
12631     len += strlen(remote);
12632     len += 16;
12633
12634     if ( hdrlist ) {
12635         for (i = 0; hdrlist[i]; i++)
12636             len += strlen(hdrlist[i]) + 2;
12637     }
12638     len += strlen(http_host_port) + 8;
12639
12640     if (agent)
12641       len += 13 + strlen(agent);
12642     if (user) {
12643         if (!pwd) {
12644             readpass("Password: ",passwd,64);
12645             pwd = passwd;
12646         }
12647         ckmakmsg(b64in,sizeof(b64in),user,":",pwd,NULL);
12648         j = b8tob64(b64in,strlen(b64in),b64out,256);
12649         memset(pwd,0,strlen(pwd));
12650         if (j < 0)
12651           return(-1);
12652         b64out[j] = '\0';
12653         len += j + 24;
12654     }
12655     len += 32;                          /* Date: */
12656 #ifdef HTTP_CLOSE
12657     len += 19;                          /* Connection: close */
12658 #endif
12659     len += 3;                           /* blank line + null */
12660
12661     request = malloc(len);
12662     if (!request)
12663       return(-1);
12664
12665     sprintf(request,"DELETE %s %s\r\n",remote,HTTP_VERSION);
12666     ckstrncat(request,"Date: ",len);
12667 #ifdef CMDATE2TM
12668     ckstrncat(request,http_now(),len);
12669 #else
12670     ckstrncat(request,...,len);
12671 #endif /* CMDATE2TM */
12672     ckstrncat(request,"\r\n",len);
12673     ckstrncat(request,"Host: ", len);
12674     ckstrncat(request,http_host_port, len);
12675     ckstrncat(request,"\r\n",len);
12676     if (agent) {
12677         ckstrncat(request,"User-agent: ",len);
12678         ckstrncat(request,agent,len);
12679         ckstrncat(request,"\r\n",len);
12680     }
12681     if (user) {
12682         ckstrncat(request,"Authorization: Basic ",len);
12683         ckstrncat(request,b64out,len);
12684         ckstrncat(request,"\r\n",len);
12685     }
12686     if ( hdrlist ) {
12687         for (i = 0; hdrlist[i]; i++) {
12688             ckstrncat(request,hdrlist[i],len);
12689             ckstrncat(request,"\r\n",len);
12690         }
12691     }
12692 #ifdef HTTP_CLOSE
12693     ckstrncat(request,"Connection: close\r\n",len);
12694 #endif
12695     ckstrncat(request,"\r\n",len);
12696   delreq:
12697     if (http_tol((CHAR *)request,strlen(request)) < 0)
12698     {
12699         http_close();
12700         if ( first ) {
12701             first--;
12702             http_reopen();
12703             goto delreq;
12704         }
12705         rc = -1;
12706         goto delexit;
12707     }
12708
12709     /* Process the response headers */
12710     local_t = time(NULL);
12711     nullline = 0;
12712     i = 0;
12713     len = -1;
12714     while (!nullline && (ch = http_inc(0)) >= 0 && i < HTTPBUFLEN) {
12715         buf[i] = ch;
12716         if (buf[i] == 10) {         /* found end of line */
12717             if (i > 0 && buf[i-1] == 13)
12718               i--;
12719             if (i < 1)
12720               nullline = 1;
12721             buf[i] = '\0';
12722             if (array && !nullline && hdcnt < HTTPHEADCNT)
12723                 makestr(&headers[hdcnt++],buf);
12724             if (!ckstrcmp(buf,"HTTP",4,0)) {
12725                 http_fnd = 1;
12726                 j = ckindex(" ",buf,0,0,0);
12727                 p = &buf[j];
12728                 while (isspace(*p))
12729                   p++;
12730                 switch (p[0]) {
12731                   case '1':             /* Informational message */
12732                     break;
12733                   case '2':             /* Success */
12734                     break;
12735                   case '3':             /* Redirection */
12736                   case '4':             /* Client failure */
12737                   case '5':             /* Server failure */
12738                   default:              /* Unknown */
12739                     if (!quiet)
12740                       printf("Failure: Server reports %s\n",p);
12741                     rc = -1;
12742                 }
12743                 http_set_code_reply(p);
12744             } else {
12745                 if (!ckstrcmp(buf,"Connection:",11,0)) {
12746                     if ( ckindex("close",buf,11,0,0) != 0 )
12747                         closecon = 1;
12748                 } else if (!ckstrcmp(buf,"Content-Length:",15,0)) {
12749                     len = atoi(&buf[16]);
12750                 } else if (!ckstrcmp(buf,"Transfer-Encoding:",18,0)) {
12751                     if ( ckindex("chunked",buf,18,0,0) != 0 )
12752                         chunked = 1;
12753                     debug(F101,"http_delete chunked","",chunked);
12754                 }
12755                 printf("%s\n",buf);
12756             }
12757             i = 0;
12758         } else {
12759             i++;
12760         }
12761     }
12762     if (ch < 0 && first) {
12763         first--;
12764         http_close();
12765         http_reopen();
12766         goto delreq;
12767     }
12768     if ( http_fnd == 0 ) {
12769         rc = -1;
12770         closecon = 1;
12771         goto delexit;
12772     }
12773
12774     /* Any response data? */
12775     if ( chunked ) {
12776         while ((len = http_get_chunk_len()) > 0) {
12777             while (len && (ch = http_inc(0)) >= 0) {
12778                 len--;
12779                 conoc((CHAR)ch);
12780             }
12781             if ((ch = http_inc(0)) != CR)
12782                 break;
12783             if ((ch = http_inc(0)) != LF)
12784                 break;
12785         }
12786     } else {
12787         while (len && (ch = http_inc(0)) >= 0) {
12788             len--;
12789             conoc((CHAR)ch);
12790         }
12791     }
12792
12793     if ( chunked ) {            /* Parse Trailing Headers */
12794         nullline = 0;
12795         while (!nullline && (ch = http_inc(0)) >= 0 && i < HTTPBUFLEN) {
12796             buf[i] = ch;
12797             if ( buf[i] == 10 ) { /* found end of line */
12798                 if (i > 0 && buf[i-1] == 13)
12799                   i--;
12800                 if (i < 1)
12801                   nullline = 1;
12802                 buf[i] = '\0';
12803                 if (array && !nullline && hdcnt < HTTPHEADCNT)
12804                     makestr(&headers[hdcnt++],buf);
12805                 if (!ckstrcmp(buf,"Connection:",11,0)) {
12806                     if ( ckindex("close",buf,11,0,0) != 0 )
12807                         closecon = 1;
12808                 }
12809                 i = 0;
12810             } else {
12811                 i++;
12812             }
12813         }
12814     }
12815
12816   delexit:
12817     if (array)
12818         http_mkarray(headers,hdcnt,array);
12819
12820     if (closecon)
12821         http_close();
12822     free(request);
12823     for (i = 0; i < hdcnt; i++) {
12824         if (headers[i])
12825           free(headers[i]);
12826     }
12827     return(rc);
12828 }
12829
12830 int
12831 #ifdef CK_ANSIC
12832 http_post(char * agent, char ** hdrlist, char * mime, char * user,
12833           char * pwd, char array, char * local, char * remote,
12834           char * dest, int stdio)
12835 #else
12836 http_post(agent, hdrlist, mime, user, pwd, array, local, remote, dest,
12837           stdio)
12838     char * agent; char ** hdrlist; char * mime; char * user;
12839     char * pwd; char array; char * local; char * remote; char * dest;
12840     int stdio;
12841 #endif /* CK_ANSIC */
12842 {
12843     char * request=NULL;
12844     int    i, j, len = 0, hdcnt = 0, rc = 0;
12845     int    ch;
12846     int    http_fnd = 0;
12847     char   buf[HTTPBUFLEN], *p;
12848     int    nullline;
12849     time_t mod_t;
12850     time_t srv_t;
12851     time_t local_t;
12852     char passwd[64];
12853     char b64in[128];
12854     char b64out[256];
12855     int  filelen;
12856     char * headers[HTTPHEADCNT];
12857     int  closecon = 0;
12858     int  chunked = 0;
12859     int  zfile = 0;
12860     int  first = 1;
12861
12862     if (httpfd == -1)
12863       return(-1);
12864
12865     if (array) {
12866         for (i = 0; i < HTTPHEADCNT; i++)
12867           headers[i] = NULL;
12868     }
12869     filelen = zchki(local);
12870     if (filelen < 0)
12871       return(-1);
12872
12873     /* Compute length of request header */
12874     len = 9;                            /* POST */
12875     len += strlen(HTTP_VERSION);
12876     len += strlen(remote);
12877     len += 16;
12878
12879     if ( hdrlist ) {
12880         for (i = 0; hdrlist[i]; i++)
12881             len += strlen(hdrlist[i]) + 2;
12882     }
12883     len += strlen(http_host_port) + 8;
12884
12885     if (agent)
12886       len += 13 + strlen(agent);
12887     if (user) {
12888         if (!pwd) {
12889             readpass("Password: ",passwd,64);
12890             pwd = passwd;
12891         }
12892         ckmakmsg(b64in,sizeof(b64in),user,":",pwd,NULL);
12893         j = b8tob64(b64in,strlen(b64in),b64out,256);
12894         memset(pwd,0,strlen(pwd));
12895         if (j < 0)
12896           return(-1);
12897         b64out[j] = '\0';
12898         len += j + 24;
12899     }
12900     len += 16 + strlen(mime);           /* Content-type: */
12901     len += 32;                          /* Content-length: */
12902     len += 32;                          /* Date: */
12903 #ifdef HTTP_CLOSE
12904     len += 19;                          /* Connection: close */
12905 #endif
12906     len += 3;                           /* blank line + null */
12907
12908     request = malloc(len);
12909     if (!request)
12910       return(-1);
12911
12912     sprintf(request,"POST %s %s\r\n",remote,HTTP_VERSION);
12913     ckstrncat(request,"Date: ",len);
12914     ckstrncat(request,http_now(),len);
12915     ckstrncat(request,"\r\n",len);
12916     ckstrncat(request,"Host: ", len);
12917     ckstrncat(request,http_host_port, len);
12918     ckstrncat(request,"\r\n",len);
12919     if (agent) {
12920         ckstrncat(request,"User-agent: ",len);
12921         ckstrncat(request,agent,len);
12922         ckstrncat(request,"\r\n",len);
12923     }
12924     if (user) {
12925         ckstrncat(request,"Authorization: Basic ",len);
12926         ckstrncat(request,b64out,len);
12927         ckstrncat(request,"\r\n",len);
12928     }
12929     if ( hdrlist ) {
12930         for (i = 0; hdrlist[i]; i++) {
12931             ckstrncat(request,hdrlist[i],len);
12932             ckstrncat(request,"\r\n",len);
12933         }
12934     }
12935     ckstrncat(request,"Content-type: ",len);
12936     ckstrncat(request,mime,len);
12937     ckstrncat(request,"\r\n",len);
12938 #ifdef HTTP_CLOSE
12939     ckstrncat(request,"Connection: close\r\n",len);
12940 #endif
12941     sprintf(buf,"Content-length: %d\r\n",filelen); /* safe */
12942     ckstrncat(request,buf,len);
12943     ckstrncat(request,"\r\n",len);
12944 #ifdef COMMENT
12945     /* This is apparently a mistake - the previous ckstrncat() already  */
12946     /* appended a blank line to the request.  There should only be one. */
12947     /* Servers are not required by RFC 2616 to ignore extraneous empty  */
12948     /* lines.  -fdc, 28 Aug 2005. */
12949     ckstrncat(request,"\r\n",len);
12950 #endif  /* COMMENT */
12951
12952     /* Now we have the contents of the file */
12953   postopen:
12954     if (zopeni(ZIFILE,local)) {
12955       postreq:
12956         if (http_tol((CHAR *)request,strlen(request)) < 0)
12957         {
12958             http_close();
12959             if ( first ) {
12960                 first--;
12961                 http_reopen();
12962                 goto postreq;
12963             }
12964             rc = -1;
12965             zclose(ZIFILE);
12966             goto postexit;
12967         }
12968
12969         i = 0;
12970         while (zchin(ZIFILE,&ch) == 0) {
12971             buf[i++] = ch;
12972             if (i == HTTPBUFLEN) {
12973                 http_tol((CHAR *)buf,HTTPBUFLEN);
12974                 i = 0;
12975             }
12976         }
12977         if (i > 0)
12978           http_tol((CHAR *)buf,HTTPBUFLEN);
12979         zclose(ZIFILE);
12980
12981         /* Process the response headers */
12982         local_t = time(NULL);
12983         nullline = 0;
12984         i = 0;
12985         len = -1;
12986         while (!nullline && (ch = http_inc(0)) >= 0 && i < HTTPBUFLEN) {
12987             buf[i] = ch;
12988             if (buf[i] == 10) {         /* found end of line */
12989                 if (i > 0 && buf[i-1] == 13)
12990                   i--;
12991                 if (i < 1)
12992                   nullline = 1;
12993                 buf[i] = '\0';
12994                 if (array && !nullline && hdcnt < HTTPHEADCNT)
12995                   makestr(&headers[hdcnt++],buf);
12996                 if (!ckstrcmp(buf,"HTTP",4,0)) {
12997                     http_fnd = 1;
12998                     j = ckindex(" ",buf,0,0,0);
12999                     p = &buf[j];
13000                     while (isspace(*p))
13001                       p++;
13002                     switch (p[0]) {
13003                       case '1':         /* Informational message */
13004                         break;
13005                       case '2':         /* Success */
13006                         break;
13007                       case '3':         /* Redirection */
13008                       case '4':         /* Client failure */
13009                       case '5':         /* Server failure */
13010                       default:          /* Unknown */
13011                         if (!quiet)
13012                           printf("Failure: Server reports %s\n",p);
13013                         rc = -1;
13014                     }
13015                     http_set_code_reply(p);
13016                 } else {
13017                     if (!ckstrcmp(buf,"Connection:",11,0)) {
13018                         if ( ckindex("close",buf,11,0,0) != 0 )
13019                             closecon = 1;
13020                     } else if (!ckstrcmp(buf,"Content-Length:",15,0)) {
13021                         len = atoi(&buf[16]);
13022                     } else if (!ckstrcmp(buf,"Transfer-Encoding:",18,0)) {
13023                         if ( ckindex("chunked",buf,18,0,0) != 0 )
13024                             chunked = 1;
13025                         debug(F101,"http_post chunked","",chunked);
13026                     }
13027                     if (stdio)
13028                         printf("%s\n",buf);
13029                 }
13030                 i = 0;
13031             } else {
13032                 i++;
13033             }
13034         }
13035         if (ch < 0 && first) {
13036             first--;
13037             http_close();
13038             http_reopen();
13039             goto postopen;
13040         }
13041         if (http_fnd == 0) {
13042             rc = -1;
13043             closecon = 1;
13044             goto postexit;
13045         }
13046
13047         /* Any response data? */
13048         if ( dest && dest[0] ) {
13049             if (zopeno(ZOFILE,dest,NULL,NULL))
13050                 zfile = 1;
13051             else
13052                 rc = -1;
13053         }
13054
13055         if ( chunked ) {
13056             while ((len = http_get_chunk_len()) > 0) {
13057                 while (len && (ch = http_inc(0)) >= 0) {
13058                     len--;
13059                     if ( zfile )
13060                         zchout(ZOFILE,(CHAR)ch);
13061                     if ( stdio )
13062                         conoc((CHAR)ch);
13063                 }
13064                 if ((ch = http_inc(0)) != CR)
13065                     break;
13066                 if ((ch = http_inc(0)) != LF)
13067                     break;
13068             }
13069         } else {
13070             while (len && (ch = http_inc(0)) >= 0) {
13071                 len--;
13072                 if ( zfile )
13073                     zchout(ZOFILE,(CHAR)ch);
13074                 if ( stdio )
13075                     conoc((CHAR)ch);
13076             }
13077         }
13078
13079         if ( zfile )
13080             zclose(ZOFILE);
13081
13082         if ( chunked ) {            /* Parse Trailing Headers */
13083             nullline = 0;
13084             while (!nullline && (ch = http_inc(0)) >= 0 && i < HTTPBUFLEN) {
13085                 buf[i] = ch;
13086                 if ( buf[i] == 10 ) { /* found end of line */
13087                     if (i > 0 && buf[i-1] == 13)
13088                       i--;
13089                     if (i < 1)
13090                       nullline = 1;
13091                     buf[i] = '\0';
13092                     if (array && !nullline && hdcnt < HTTPHEADCNT)
13093                         makestr(&headers[hdcnt++],buf);
13094                     if (!ckstrcmp(buf,"Connection:",11,0)) {
13095                         if ( ckindex("close",buf,11,0,0) != 0 )
13096                             closecon = 1;
13097                     }
13098                     i = 0;
13099                 } else {
13100                     i++;
13101                 }
13102             }
13103         }
13104     } else {
13105         rc = -1;
13106     }
13107
13108   postexit:
13109     if (array)
13110         http_mkarray(headers,hdcnt,array);
13111     if (closecon)
13112         http_close();
13113     free(request);
13114     for (i = 0; i < hdcnt; i++) {
13115         if (headers[i])
13116           free(headers[i]);
13117     }
13118     return(rc);
13119 }
13120
13121 int
13122 #ifdef CK_ANSIC
13123 http_connect(int socket, char * agent, char ** hdrlist, char * user,
13124              char * pwd, char array, char * host_port)
13125 #else
13126 http_connect(socket, agent, hdrlist, user, pwd, array, host_port)
13127     int socket;
13128     char * agent; char ** hdrlist; char * user;
13129     char * pwd; char array; char * host_port;
13130 #endif /* CK_ANSIC */
13131 {
13132     char * request=NULL;
13133     int    i, j, len = 0, hdcnt = 0, rc = 0;
13134     int    http_fnd = 0;
13135     char   buf[HTTPBUFLEN], *p, ch;
13136     int    nullline;
13137     time_t mod_t;
13138     time_t srv_t;
13139     time_t local_t;
13140     char passwd[64];
13141     char b64in[128];
13142     char b64out[256];
13143     char * headers[HTTPHEADCNT];
13144     int    connected = 0;
13145
13146     tcp_http_proxy_errno = 0;
13147
13148     if (socket == -1)
13149       return(-1);
13150
13151     if (array) {
13152         for (i = 0; i < HTTPHEADCNT; i++)
13153           headers[i] = NULL;
13154     }
13155
13156     /* Compute length of request header */
13157     len = 12;                            /* CONNECT */
13158     len += strlen(HTTP_VERSION);
13159     len += strlen(host_port);
13160     len += (int) strlen(http_host_port) + 8;
13161     len += 16;
13162     len += strlen("Proxy-Connection: Keep-Alive\r\n");
13163     if ( hdrlist ) {
13164         for (i = 0; hdrlist[i]; i++)
13165             len += strlen(hdrlist[i]) + 2;
13166     }
13167     if (agent && agent[0])
13168       len += 13 + strlen(agent);
13169     if (user && user[0]) {
13170         if (!pwd) {
13171             readpass("Password: ",passwd,64);
13172             pwd = passwd;
13173         }
13174         ckmakmsg(b64in,sizeof(b64in),user,":",pwd,NULL);
13175         j = b8tob64(b64in,strlen(b64in),b64out,256);
13176         memset(pwd,0,strlen(pwd));
13177         if (j < 0)
13178           return(-1);
13179         b64out[j] = '\0';
13180         len += j + 72;
13181     }
13182     len += 32;                          /* Date: */
13183     len += 3;                           /* blank line + null */
13184
13185     request = malloc(len);
13186     if (!request)
13187       return(-1);
13188
13189     sprintf(request,"CONNECT %s %s\r\n",host_port,HTTP_VERSION);
13190     ckstrncat(request,"Date: ",len);
13191 #ifdef CMDATE2TM
13192     ckstrncat(request,http_now(),len);
13193 #else
13194     strcat(request,...);
13195 #endif /* CMDATE2TM */
13196     ckstrncat(request,"\r\n",len);
13197     ckstrncat(request,"Host: ", len);
13198     ckstrncat(request,http_host_port, len);
13199     ckstrncat(request,"\r\n",len);
13200     if (agent && agent[0]) {
13201         ckstrncat(request,"User-agent: ",len);
13202         ckstrncat(request,agent,len);
13203         ckstrncat(request,"\r\n",len);
13204     }
13205     if (user && user[0]) {
13206         ckstrncat(request,"Proxy-authorization: Basic ",len);
13207         ckstrncat(request,b64out,len);
13208         ckstrncat(request,"\r\n",len);
13209         ckstrncat(request,"Extension: Security/Remote-Passphrase\r\n",len);
13210     }
13211     ckstrncat(request,"Proxy-Connection: Keep-Alive\r\n",len);
13212     if ( hdrlist ) {
13213         for (i = 0; hdrlist[i]; i++) {
13214             ckstrncat(request,hdrlist[i],len);
13215             ckstrncat(request,"\r\n",len);
13216         }
13217     }
13218     ckstrncat(request,"\r\n",len);
13219     len = strlen(request);
13220
13221 #ifdef TCPIPLIB
13222     /* Send request */
13223     if (socket_write(socket,(CHAR *)request,strlen(request)) < 0) {
13224       rc = -1;
13225       goto connexit;
13226     }
13227 #else
13228     if (write(socket,(CHAR *)request,strlen(request)) < 0) { /* Send request */
13229         rc = -1;
13230         goto connexit;
13231     }
13232 #endif /* TCPIPLIB */
13233
13234     /* Process the response headers */
13235     local_t = time(NULL);
13236     nullline = 0;
13237     i = 0;
13238     while (!nullline &&
13239 #ifdef TCPIPLIB
13240            (socket_read(socket,&ch,1) == 1) &&
13241 #else
13242            (read(socket,&ch,1) == 1) &&
13243 #endif /* TCPIPLIB */
13244            i < HTTPBUFLEN) {
13245         buf[i] = ch;
13246         if (buf[i] == 10) {         /* found end of line */
13247             if (i > 0 && buf[i-1] == 13)
13248               i--;
13249             if (i < 1)
13250               nullline = 1;
13251             buf[i] = '\0';
13252
13253             if (array && !nullline && hdcnt < HTTPHEADCNT)
13254                 makestr(&headers[hdcnt++],buf);
13255             if (!ckstrcmp(buf,"HTTP",4,0)) {
13256                 http_fnd = 1;
13257                 j = ckindex(" ",buf,0,0,0);
13258                 p = &buf[j];
13259                 while (isspace(*p))
13260                   p++;
13261                 tcp_http_proxy_errno = atoi(p);
13262                 switch (p[0]) {
13263                   case '1':             /* Informational message */
13264                     break;
13265                   case '2':             /* Success */
13266                     connected = 1;
13267                     break;
13268                   case '3':             /* Redirection */
13269                   case '4':             /* Client failure */
13270                   case '5':             /* Server failure */
13271                   default:              /* Unknown */
13272                     if (!quiet)
13273                       printf("Failure: Server reports %s\n",p);
13274                     rc = -1;
13275                 }
13276                 http_set_code_reply(p);
13277             } else {
13278                 printf("%s\n",buf);
13279             }
13280             i = 0;
13281         } else {
13282             i++;
13283         }
13284     }
13285     if ( http_fnd == 0 )
13286         rc = -1;
13287
13288     if (array)
13289         http_mkarray(headers,hdcnt,array);
13290
13291   connexit:
13292     if ( !connected ) {
13293         if ( socket == ttyfd ) {
13294             ttclos(0);
13295         }
13296         else if ( socket == httpfd ) {
13297             http_close();
13298         }
13299     }
13300
13301     free(request);
13302     for (i = 0; i < hdcnt; i++) {
13303         if (headers[i])
13304           free(headers[i]);
13305     }
13306     return(rc);
13307 }
13308 #endif /* NOHTTP */
13309
13310 #ifdef CK_DNS_SRV
13311
13312 #define INCR_CHECK(x,y) x += y; if (x > size + answer.bytes) goto dnsout
13313 #define CHECK(x,y) if (x + y > size + answer.bytes) goto dnsout
13314 #define NTOHSP(x,y) x[0] << 8 | x[1]; x += y
13315
13316 #ifndef CKQUERYTYPE
13317 #ifdef UNIXWARE
13318 #ifndef UW7
13319 #define CKQUERYTYPE CHAR
13320 #endif /* UW7 */
13321 #endif /* UNIXWARE */
13322 #endif /* CKQUERYTYPE */
13323
13324 #ifndef CKQUERYTYPE
13325 #define CKQUERYTYPE char
13326 #endif /* CKQUERYTYPE */
13327
13328 /* 1 is success, 0 is failure */
13329 int
13330 locate_srv_dns(host, service, protocol, addr_pp, naddrs)
13331     char *host;
13332     char *service;
13333     char *protocol;
13334     struct sockaddr **addr_pp;
13335     int *naddrs;
13336 {
13337     int nout, j, count;
13338     union {
13339         unsigned char bytes[2048];
13340         HEADER hdr;
13341     } answer;
13342     unsigned char *p=NULL;
13343     CKQUERYTYPE query[MAX_DNS_NAMELEN];
13344 #ifdef CK_ANSIC
13345     const char * h;
13346 #else
13347     char * h;
13348 #endif /* CK_ANSIC */
13349     struct sockaddr *addr = NULL;
13350     struct sockaddr_in *sin = NULL;
13351     struct hostent *hp = NULL;
13352     int type, class;
13353     int priority, weight, size, len, numanswers, numqueries, rdlen;
13354     unsigned short port;
13355 #ifdef CK_ANSIC
13356     const
13357 #endif /* CK_ANSIC */
13358       int hdrsize = sizeof(HEADER);
13359     struct srv_dns_entry {
13360         struct srv_dns_entry *next;
13361         int priority;
13362         int weight;
13363         unsigned short port;
13364         char *host;
13365     };
13366     struct srv_dns_entry *head = NULL;
13367     struct srv_dns_entry *srv = NULL, *entry = NULL;
13368     char * s = NULL;
13369
13370     nout = 0;
13371     addr = (struct sockaddr *) malloc(sizeof(struct sockaddr));
13372     if (addr == NULL)
13373       return 0;
13374
13375     count = 1;
13376
13377     /*
13378      * First build a query of the form:
13379      *
13380      *   service.protocol.host
13381      *
13382      * which will most likely be something like:
13383      *
13384      *   _telnet._tcp.host
13385      *
13386      */
13387     if (((int)strlen(service) + strlen(protocol) + strlen(host) + 5)
13388         > MAX_DNS_NAMELEN
13389         )
13390       goto dnsout;
13391
13392     /* Realm names don't (normally) end with ".", but if the query
13393        doesn't end with "." and doesn't get an answer as is, the
13394        resolv code will try appending the local domain.  Since the
13395        realm names are absolutes, let's stop that.
13396
13397        But only if a name has been specified.  If we are performing
13398        a search on the prefix alone then the intention is to allow
13399        the local domain or domain search lists to be expanded.
13400     */
13401     h = host + strlen (host);
13402     ckmakxmsg(query, sizeof(query), "_",service,"._",protocol,".", host,
13403               ((h > host) && (h[-1] != '.')?".":NULL),
13404                NULL,NULL,NULL,NULL,NULL);
13405
13406     size = res_search(query, C_IN, T_SRV, answer.bytes, sizeof(answer.bytes));
13407
13408     if (size < hdrsize)
13409       goto dnsout;
13410
13411     /* We got a reply - See how many answers it contains. */
13412
13413     p = answer.bytes;
13414
13415     numqueries = ntohs(answer.hdr.qdcount);
13416     numanswers = ntohs(answer.hdr.ancount);
13417
13418     p += sizeof(HEADER);
13419
13420     /*
13421      * We need to skip over all of the questions, so we have to iterate
13422      * over every query record.  dn_expand() is able to tell us the size
13423      * of compressed DNS names, so we use it.
13424      */
13425     while (numqueries--) {
13426         len = dn_expand(answer.bytes,answer.bytes+size,p,query,sizeof(query));
13427         if (len < 0)
13428           goto dnsout;
13429         INCR_CHECK(p, len + 4);
13430     }
13431
13432     /*
13433      * We're now pointing at the answer records.  Only process them if
13434      * they're actually T_SRV records (they might be CNAME records,
13435      * for instance).
13436      *
13437      * But in a DNS reply, if you get a CNAME you always get the associated
13438      * "real" RR for that CNAME.  RFC 1034, 3.6.2:
13439      *
13440      * CNAME RRs cause special action in DNS software.  When a name server
13441      * fails to find a desired RR in the resource set associated with the
13442      * domain name, it checks to see if the resource set consists of a CNAME
13443      * record with a matching class.  If so, the name server includes the CNAME
13444      * record in the response and restarts the query at the domain name
13445      * specified in the data field of the CNAME record.  The one exception to
13446      * this rule is that queries which match the CNAME type are not restarted.
13447      *
13448      * In other words, CNAMEs do not need to be expanded by the client.
13449      */
13450     while (numanswers--) {
13451
13452         /* First is the name; use dn_expand() to get the compressed size. */
13453         len = dn_expand(answer.bytes,answer.bytes+size,p,query,sizeof(query));
13454         if (len < 0)
13455           goto dnsout;
13456         INCR_CHECK(p, len);
13457
13458         CHECK(p,2);                     /* Query type */
13459         type = NTOHSP(p,2);
13460
13461         CHECK(p, 6);                    /* Query class */
13462         class = NTOHSP(p,6);            /* Also skip over 4-byte TTL */
13463
13464         CHECK(p,2);                     /* Record data length */
13465         rdlen = NTOHSP(p,2);
13466         /*
13467          * If this is an SRV record, process it.  Record format is:
13468          *
13469          * Priority
13470          * Weight
13471          * Port
13472          * Server name
13473          */
13474         if (class == C_IN && type == T_SRV) {
13475             CHECK(p,2);
13476             priority = NTOHSP(p,2);
13477             CHECK(p, 2);
13478             weight = NTOHSP(p,2);
13479             CHECK(p, 2);
13480             port = NTOHSP(p,2);
13481             len = dn_expand(answer.
13482                             bytes,
13483                             answer.bytes + size,
13484                             p,
13485                             query,
13486                             sizeof(query)
13487                             );
13488             if (len < 0)
13489               goto dnsout;
13490             INCR_CHECK(p, len);
13491             /*
13492              * We got everything.  Insert it into our list, but make sure
13493              * it's in the right order.  Right now we don't do anything
13494              * with the weight field
13495              */
13496             srv = (struct srv_dns_entry *)malloc(sizeof(struct srv_dns_entry));
13497             if (srv == NULL)
13498               goto dnsout;
13499
13500             srv->priority = priority;
13501             srv->weight = weight;
13502             srv->port = port;
13503             makestr(&s,(char *)query);  /* strdup() is not portable */
13504             srv->host = s;
13505
13506             if (head == NULL || head->priority > srv->priority) {
13507                 srv->next = head;
13508                 head = srv;
13509             } else
13510                 /*
13511                  * Confusing.  Insert an entry into this spot only if:
13512                  *  . The next person has a higher priority (lower
13513                  *    priorities are preferred), or:
13514                  *  . There is no next entry (we're at the end)
13515                  */
13516               for (entry = head; entry != NULL; entry = entry->next)
13517                 if ((entry->next &&
13518                      entry->next->priority > srv->priority) ||
13519                     entry->next == NULL) {
13520                     srv->next = entry->next;
13521                     entry->next = srv;
13522                     break;
13523                 }
13524         } else
13525           INCR_CHECK(p, rdlen);
13526     }
13527
13528     /*
13529      * Now we've got a linked list of entries sorted by priority.
13530      * Start looking up A records and returning addresses.
13531      */
13532     if (head == NULL)
13533       goto dnsout;
13534
13535     for (entry = head; entry != NULL; entry = entry->next) {
13536         hp = gethostbyname(entry->host);
13537         if (hp != 0) {
13538
13539             /* Watch out - memset() and memcpy() are not portable... */
13540
13541             switch (hp->h_addrtype) {
13542               case AF_INET:
13543                 for (j = 0; hp->h_addr_list[j]; j++) {
13544                     sin = (struct sockaddr_in *) &addr[nout++];
13545                     memset ((char *) sin, 0, sizeof (struct sockaddr));
13546                     sin->sin_family = hp->h_addrtype;
13547                     sin->sin_port = htons(entry->port);
13548                     memcpy((char *) &sin->sin_addr,
13549                            (char *) hp->h_addr_list[j],
13550                            sizeof(struct in_addr));             /* safe */
13551                     if (nout + 1 >= count) {
13552                         count += 5;
13553                         addr = (struct sockaddr *)
13554                           realloc((char *) addr,
13555                                   sizeof(struct sockaddr) * count);
13556                         if (!addr)
13557                           goto dnsout;
13558                     }
13559                 }
13560                 break;
13561               default:
13562                 break;
13563             }
13564         }
13565     }
13566     for (entry = head; entry != NULL;) {
13567         free(entry->host);
13568         entry->host = NULL;
13569         srv = entry;
13570         entry = entry->next;
13571         free(srv);
13572         srv = NULL;
13573     }
13574
13575   dnsout:
13576     if (srv)
13577       free(srv);
13578
13579     if (nout == 0) {                    /* No good servers */
13580         if (addr)
13581           free(addr);
13582         return 0;
13583     }
13584     *addr_pp = addr;
13585     *naddrs = nout;
13586     return 1;
13587 }
13588 #undef INCR_CHECK
13589 #undef CHECK
13590 #undef NTOHSP
13591
13592 #define INCR_CHECK(x, y) x += y; if (x > size + answer.bytes) \
13593                          return 0
13594 #define CHECK(x, y) if (x + y > size + answer.bytes) \
13595                          return 0
13596 #define NTOHSP(x, y) x[0] << 8 | x[1]; x += y
13597
13598 int
13599 locate_txt_rr(prefix, name, retstr)
13600     char *prefix, *name;
13601     char **retstr;
13602 {
13603     union {
13604         unsigned char bytes[2048];
13605         HEADER hdr;
13606     } answer;
13607     unsigned char *p;
13608     char host[MAX_DNS_NAMELEN], *h;
13609     int size;
13610     int type, class, numanswers, numqueries, rdlen, len;
13611
13612     /*
13613      * Form our query, and send it via DNS
13614      */
13615
13616     if (name == NULL || name[0] == '\0') {
13617         strcpy(host,prefix);
13618     } else {
13619         if ( strlen(prefix) + strlen(name) + 3 > MAX_DNS_NAMELEN )
13620             return 0;
13621
13622         /* Realm names don't (normally) end with ".", but if the query
13623            doesn't end with "." and doesn't get an answer as is, the
13624            resolv code will try appending the local domain.  Since the
13625            realm names are absolutes, let's stop that.
13626
13627            But only if a name has been specified.  If we are performing
13628            a search on the prefix alone then the intention is to allow
13629            the local domain or domain search lists to be expanded.
13630         */
13631         h = host + strlen (host);
13632         ckmakmsg(host,sizeof(host),prefix, ".", name,
13633                  ((h > host) && (h[-1] != '.'))?".":NULL);
13634
13635     }
13636     size = res_search(host, C_IN, T_TXT, answer.bytes, sizeof(answer.bytes));
13637
13638     if (size < 0)
13639         return 0;
13640
13641     p = answer.bytes;
13642
13643     numqueries = ntohs(answer.hdr.qdcount);
13644     numanswers = ntohs(answer.hdr.ancount);
13645
13646     p += sizeof(HEADER);
13647
13648     /*
13649      * We need to skip over the questions before we can get to the answers,
13650      * which means we have to iterate over every query record.  We use
13651      * dn_expand to tell us how long each compressed name is.
13652      */
13653
13654     while (numqueries--) {
13655         len = dn_expand(answer.bytes, answer.bytes + size, p, host,
13656                          sizeof(host));
13657         if (len < 0)
13658             return 0;
13659         INCR_CHECK(p, len + 4);         /* Name plus type plus class */
13660     }
13661
13662     /*
13663      * We're now pointing at the answer records.  Process the first
13664      * TXT record we find.
13665      */
13666
13667     while (numanswers--) {
13668
13669         /* First the name; use dn_expand to get the compressed size */
13670         len = dn_expand(answer.bytes, answer.bytes + size, p,
13671                         host, sizeof(host));
13672         if (len < 0)
13673             return 0;
13674         INCR_CHECK(p, len);
13675
13676         /* Next is the query type */
13677         CHECK(p, 2);
13678         type = NTOHSP(p,2);
13679
13680         /* Next is the query class; also skip over 4 byte TTL */
13681         CHECK(p,6);
13682         class = NTOHSP(p,6);
13683
13684         /* Record data length - make sure we aren't truncated */
13685
13686         CHECK(p,2);
13687         rdlen = NTOHSP(p,2);
13688
13689         if (p + rdlen > answer.bytes + size)
13690             return 0;
13691
13692         /*
13693          * If this is a TXT record, return the string.  Note that the
13694          * string has a 1-byte length in the front
13695          */
13696         /* XXX What about flagging multiple TXT records as an error?  */
13697
13698         if (class == C_IN && type == T_TXT) {
13699             len = *p++;
13700             if (p + len > answer.bytes + size)
13701                 return 0;
13702             *retstr = malloc(len + 1);
13703             if (*retstr == NULL)
13704                 return ENOMEM;
13705             strncpy(*retstr, (char *) p, len);
13706             (*retstr)[len] = '\0';
13707             /* Avoid a common error. */
13708             if ( (*retstr)[len-1] == '.' )
13709                 (*retstr)[len-1] = '\0';
13710             return 1;
13711         }
13712     }
13713
13714     return 0;
13715 }
13716 #undef INCR_CHECK
13717 #undef CHECK
13718 #undef NTOHSP
13719 #endif /* CK_DNS_SRV */
13720
13721 #ifdef TNCODE
13722 #ifdef CK_FORWARD_X
13723 #ifdef UNIX
13724 #include <sys/un.h>
13725 #define FWDX_UNIX_SOCK
13726 #ifndef AF_LOCAL
13727 #define AF_LOCAL AF_UNIX
13728 #endif
13729 #ifndef PF_LOCAL
13730 #define PF_LOCAL PF_UNIX
13731 #endif
13732 #ifndef SUN_LEN
13733 /* Evaluate to actual length of the `sockaddr_un' structure.  */
13734 #define SUN_LEN(ptr) ((size_t) (((struct sockaddr_un *) 0)->sun_path)         \
13735                       + strlen ((ptr)->sun_path))
13736 #endif
13737 #endif /* UNIX */
13738 int
13739 fwdx_create_listen_socket(screen) int screen; {
13740 #ifdef NOPUTENV
13741     return(-1);
13742 #else /* NOPUTENV */
13743     struct sockaddr_in saddr;
13744     int display, port, sock=-1, i;
13745     static char env[512];
13746
13747     /*
13748      * X Windows Servers support multiple displays by listening on
13749      * one socket per display.  Display 0 is port 6000; Display 1 is
13750      * port 6001; etc.
13751      *
13752      * We start by trying to open port 6001 so that display 0 is
13753      * reserved for the local X Windows Server.
13754      */
13755
13756     for ( display=1; display < 1000 ; display++  ) {
13757
13758         if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
13759             debug(F111,"fwdx_create_listen_socket()","socket() < 0",sock);
13760             return(-1);
13761         }
13762
13763         port = 6000 + display;
13764         bzero((char *)&saddr, sizeof(saddr));
13765         saddr.sin_family = AF_INET;
13766         saddr.sin_addr.s_addr = inet_addr(myipaddr);
13767         saddr.sin_port = htons(port);
13768
13769         if (bind(sock, (struct sockaddr *)&saddr, sizeof(saddr)) < 0) {
13770             i = errno;                  /* Save error code */
13771 #ifdef TCPIPLIB
13772             socket_close(sock);
13773 #else /* TCPIPLIB */
13774             close(sock);
13775 #endif /* TCPIPLIB */
13776             sock = -1;
13777             debug(F110,"fwdx_create_listen_socket()","bind() < 0",0);
13778             continue;
13779         }
13780
13781         debug(F100,"fdwx_create_listen_socket() bind OK","",0);
13782         break;
13783     }
13784
13785     if ( display > 1000 ) {
13786         debug(F100,"fwdx_create_listen_socket() Out of Displays","",0);
13787         return(-1);
13788     }
13789
13790     if (listen(sock, 5) < 0) {
13791         i = errno;                  /* Save error code */
13792 #ifdef TCPIPLIB
13793         socket_close(sock);
13794 #else /* TCPIPLIB */
13795         close(sock);
13796 #endif /* TCPIPLIB */
13797         debug(F101,"fdwx_create_listen_socket() listen() errno","",errno);
13798         return(-1);
13799     }
13800     debug(F100,"fwdx_create_listen_socket() listen OK","",0);
13801
13802     TELOPT_SB(TELOPT_FORWARD_X).forward_x.listen_socket = sock;
13803     if (!myipaddr[0])
13804         getlocalipaddr();
13805     if ( myipaddr[0] )
13806         ckmakxmsg(env,sizeof(env),"DISPLAY=",myipaddr,":",
13807                   ckuitoa(display),":",ckuitoa(screen),
13808                   NULL,NULL,NULL,NULL,NULL,NULL);
13809     else
13810         ckmakmsg(env,sizeof(env),"DISPLAY=",ckuitoa(display),":",
13811                  ckuitoa(screen));
13812     putenv(env);
13813     return(0);
13814 #endif /* NOPUTENV */
13815 }
13816
13817
13818 int
13819 fwdx_open_client_channel(channel) int channel; {
13820     char * env;
13821     struct sockaddr_in saddr;
13822 #ifdef FWDX_UNIX_SOCK
13823     struct sockaddr_un saddr_un = { AF_LOCAL };
13824 #endif /* FWDX_UNIX_SOCK */
13825     int colon, dot, display, port, sock, i, screen;
13826     int family;
13827     char buf[256], * host=NULL, * rest=NULL;
13828 #ifdef TCP_NODELAY
13829     int on=1;
13830 #endif /* TCP_NODELAY */
13831
13832     debug(F111,"fwdx_create_client_channel()","channel",channel);
13833
13834     for ( i=0; i<MAXFWDX ; i++ ) {
13835         if (TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[i].id == channel) {
13836             /* Already open */
13837             debug(F110,"fwdx_create_client_channel()","already open",0);
13838             return(0);
13839         }
13840     }
13841
13842     env = getenv("DISPLAY");
13843     if ( !env )
13844       env = (char *)tn_get_display();
13845     if ( env )
13846       ckstrncpy(buf,env,256);
13847     else
13848       ckstrncpy(buf,"127.0.0.1:0.0",256);
13849
13850     bzero((char *)&saddr,sizeof(saddr));
13851     saddr.sin_family = AF_INET;
13852
13853     if (!fwdx_parse_displayname(buf,
13854                                 &family,
13855                                 &host,
13856                                 &display,
13857                                 &screen,
13858                                 &rest
13859                                 )
13860         ) {
13861         if ( host ) free(host);
13862         if ( rest ) free(rest);
13863         return(0);
13864     }
13865     if (rest) free(rest);
13866
13867 #ifndef FWDX_UNIX_SOCK
13868   /* if $DISPLAY indicates use of unix domain sockets, but we don't support it,
13869    * we change things to use inet sockets on the ip loopback interface instead,
13870    * and hope that it works.
13871    */
13872     if (family == FamilyLocal) {
13873         debug(F100,"fwdx_create_client_channel() FamilyLocal","",0);
13874         family = FamilyInternet;
13875         if (host) free(host);
13876         if (host = malloc(strlen("localhost") + 1))
13877             strcpy(host, "localhost");
13878         else {
13879             return(-1);
13880         }
13881     }
13882 #else /* FWDX_UNIX_SOCK */
13883     if (family == FamilyLocal) {
13884         if (host) free(host);
13885         sock = socket(PF_LOCAL, SOCK_STREAM, 0);
13886         if (sock < 0)
13887             return(-1);
13888
13889         ckmakmsg(buf,sizeof(buf),"/tmp/.X11-unix/X",ckitoa(display),NULL,NULL);
13890         strncpy(saddr_un.sun_path, buf, sizeof(saddr_un.sun_path));
13891         if (connect(sock,(struct sockaddr *)&saddr_un, SUN_LEN(&saddr_un)) < 0)
13892           return(-1);
13893     } else
13894 #endif  /* FWDX_UNIX_SOCK */
13895     {
13896         /* Otherwise, we are assuming FamilyInternet */
13897         if (host) {
13898             ckstrncpy(buf,host,sizeof(buf));
13899             free(host);
13900         } else
13901             ckstrncpy(buf,myipaddr,sizeof(buf));
13902
13903         debug(F111,"fwdx_create_client_channel()","display",display);
13904
13905         port = 6000 + display;
13906         saddr.sin_port = htons(port);
13907
13908         debug(F110,"fwdx_create_client_channel() ip-address",buf,0);
13909         saddr.sin_addr.s_addr = inet_addr(buf);
13910         if ( saddr.sin_addr.s_addr == (unsigned long) -1
13911 #ifdef INADDR_NONE
13912              || saddr.sin_addr.s_addr == INADDR_NONE
13913 #endif /* INADDR_NONE */
13914              )
13915         {
13916             struct hostent *host;
13917             host = gethostbyname(buf);
13918             if ( host == NULL )
13919                 return(-1);
13920             host = ck_copyhostent(host);
13921 #ifdef HADDRLIST
13922 #ifdef h_addr
13923             /* This is for trying multiple IP addresses - see <netdb.h> */
13924             if (!(host->h_addr_list))
13925                 return(-1);
13926             bcopy(host->h_addr_list[0],
13927                    (caddr_t)&saddr.sin_addr,
13928                    host->h_length
13929                    );
13930 #else
13931             bcopy(host->h_addr, (caddr_t)&saddr.sin_addr, host->h_length);
13932 #endif /* h_addr */
13933 #else  /* HADDRLIST */
13934             bcopy(host->h_addr, (caddr_t)&saddr.sin_addr, host->h_length);
13935 #endif /* HADDRLIST */
13936         }
13937
13938         if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
13939             debug(F111,"fwdx_create_client_channel()","socket() < 0",sock);
13940             return(-1);
13941         }
13942
13943         if ( connect(sock, (struct sockaddr *)&saddr, sizeof(saddr)) < 0) {
13944             debug(F110,"fwdx_create_client_channel()","connect() failed",0);
13945 #ifdef TCPIPLIB
13946             socket_close(sock);
13947 #else /* TCPIPLIB */
13948             close(sock);
13949 #endif /* TCPIPLIB */
13950             return(-1);
13951         }
13952
13953 #ifdef TCP_NODELAY
13954         setsockopt(sock,IPPROTO_TCP,TCP_NODELAY,(char *)&on,sizeof(on));
13955 #endif /* TCP_NODELAY */
13956     }
13957
13958     for (i = 0; i < MAXFWDX; i++) {
13959      if (TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[i].id == -1) {
13960          TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[i].fd = sock;
13961          TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[i].id = channel;
13962        TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[i].need_to_send_xauth = 1;
13963          debug(F111,"fwdx_create_client_channel()","socket",sock);
13964          return(0);
13965      }
13966     }
13967     return(-1);
13968 }
13969
13970 int
13971 fwdx_server_avail() {
13972     char * env;
13973     struct sockaddr_in saddr;
13974 #ifdef FWDX_UNIX_SOCK
13975     struct sockaddr_un saddr_un = { AF_LOCAL };
13976 #endif  /* FWDX_UNIX_SOCK */
13977     int colon, dot, display, port, sock, i, screen;
13978     char buf[256], *host=NULL, *rest=NULL;
13979 #ifdef TCP_NODELAY
13980     int on=1;
13981 #endif /* TCP_NODELAY */
13982     int family;
13983
13984     env = getenv("DISPLAY");
13985     if ( !env )
13986       env = (char *)tn_get_display();
13987     if ( env )
13988       ckstrncpy(buf,env,256);
13989     else
13990       ckstrncpy(buf,"127.0.0.1:0.0",256);
13991
13992     bzero((char *)&saddr,sizeof(saddr));
13993     saddr.sin_family = AF_INET;
13994
13995     if (!fwdx_parse_displayname(buf,&family,&host,&display,&screen,&rest)) {
13996         if ( host ) free(host);
13997         if ( rest ) free(rest);
13998         return(0);
13999     }
14000     if (rest) free(rest);
14001
14002 #ifndef FWDX_UNIX_SOCK
14003   /* if $DISPLAY indicates use of unix domain sockets, but we don't support it,
14004    * we change things to use inet sockets on the ip loopback interface instead,
14005    * and hope that it works.
14006    */
14007     if (family == FamilyLocal) {
14008         family = FamilyInternet;
14009         if (host) free(host);
14010         if (host = malloc(strlen("localhost") + 1))
14011             strcpy(host, "localhost");
14012         else {
14013             return(-1);
14014         }
14015     }
14016 #else /* FWDX_UNIX_SOCK */
14017     if (family == FamilyLocal) {
14018         debug(F100,"fwdx_server_avail() FamilyLocal","",0);
14019         if (host) free(host);
14020         sock = socket(PF_LOCAL, SOCK_STREAM, 0);
14021         if (sock < 0)
14022             return(0);
14023
14024         ckmakmsg(buf,sizeof(buf),"/tmp/.X11-unix/X",ckitoa(display),NULL,NULL);
14025         strncpy(saddr_un.sun_path, buf, sizeof(saddr_un.sun_path));
14026         if (connect(sock,(struct sockaddr *)&saddr_un,SUN_LEN(&saddr_un)) < 0)
14027             return(0);
14028         close(sock);
14029         return(1);
14030     }
14031 #endif  /* FWDX_UNIX_SOCK */
14032
14033     /* Otherwise, we are assuming FamilyInternet */
14034     if (host) {
14035         ckstrncpy(buf,host,sizeof(buf));
14036         free(host);
14037     } else
14038         ckstrncpy(buf,myipaddr,sizeof(buf));
14039
14040     debug(F111,"fwdx_server_avail()","display",display);
14041
14042     port = 6000 + display;
14043     saddr.sin_port = htons(port);
14044
14045     debug(F110,"fwdx_server_avail() ip-address",buf,0);
14046     saddr.sin_addr.s_addr = inet_addr(buf);
14047     if ( saddr.sin_addr.s_addr == (unsigned long) -1
14048 #ifdef INADDR_NONE
14049          || saddr.sin_addr.s_addr == INADDR_NONE
14050 #endif /* INADDR_NONE */
14051          )
14052     {
14053         struct hostent *host;
14054         host = gethostbyname(buf);
14055         if ( host == NULL ) {
14056             debug(F110,"fwdx_server_avail() gethostbyname() failed",
14057                    myipaddr,0);
14058             return(-1);
14059         }
14060         host = ck_copyhostent(host);
14061 #ifdef HADDRLIST
14062 #ifdef h_addr
14063         /* This is for trying multiple IP addresses - see <netdb.h> */
14064         if (!(host->h_addr_list))
14065             return(-1);
14066         bcopy(host->h_addr_list[0],
14067                (caddr_t)&saddr.sin_addr,
14068                host->h_length
14069                );
14070 #else
14071         bcopy(host->h_addr, (caddr_t)&saddr.sin_addr, host->h_length);
14072 #endif /* h_addr */
14073 #else  /* HADDRLIST */
14074         bcopy(host->h_addr, (caddr_t)&saddr.sin_addr, host->h_length);
14075 #endif /* HADDRLIST */
14076     }
14077
14078     if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
14079         debug(F111,"fwdx_server_avail()","socket() < 0",sock);
14080         return(0);
14081     }
14082
14083     if ( connect(sock, (struct sockaddr *)&saddr, sizeof(saddr)) < 0) {
14084         debug(F110,"fwdx_server_avail()","connect() failed",0);
14085 #ifdef TCPIPLIB
14086         socket_close(sock);
14087 #else /* TCPIPLIB */
14088         close(sock);
14089 #endif /* TCPIPLIB */
14090         return(0);
14091     }
14092
14093 #ifdef TCPIPLIB
14094     socket_close(sock);
14095 #else /* TCPIPLIB */
14096     close(sock);
14097 #endif /* TCPIPLIB */
14098     return(1);
14099 }
14100
14101 int
14102 fwdx_open_server_channel() {
14103     int sock, ready_to_accept, sock2,channel,i;
14104 #ifdef TCP_NODELAY
14105     int on=1;
14106 #endif /* TCP_NODELAY */
14107 #ifdef UCX50
14108     static u_int saddrlen;
14109 #else
14110     static SOCKOPT_T saddrlen;
14111 #endif /* UCX50 */
14112     struct sockaddr_in saddr;
14113     char sb[8];
14114     extern char tn_msg[];
14115 #ifdef BSDSELECT
14116     fd_set rfds;
14117     struct timeval tv;
14118 #else
14119 #ifdef BELLSELCT
14120     fd_set rfds;
14121 #else
14122     fd_set rfds;
14123     struct timeval {
14124         long tv_sec;
14125         long tv_usec;
14126     } tv;
14127 #endif /* BELLSELECT */
14128 #endif /* BSDSELECT */
14129     unsigned short nchannel;
14130     unsigned char * p;
14131
14132     sock = TELOPT_SB(TELOPT_FORWARD_X).forward_x.listen_socket;
14133
14134   try_again:
14135
14136 #ifdef BSDSELECT
14137     tv.tv_sec  = tv.tv_usec = 0L;
14138     tv.tv_usec = 50;
14139     FD_ZERO(&rfds);
14140     FD_SET(sock, &rfds);
14141     ready_to_accept =
14142         ((select(FD_SETSIZE,
14143 #ifdef HPUX
14144 #ifdef HPUX1010
14145                   (fd_set *)
14146 #else
14147
14148                   (int *)
14149 #endif /* HPUX1010 */
14150 #else
14151 #ifdef __DECC
14152                   (fd_set *)
14153 #endif /* __DECC */
14154 #endif /* HPUX */
14155                   &rfds, NULL, NULL, &tv) > 0) &&
14156           FD_ISSET(sock, &rfds));
14157 #else /* BSDSELECT */
14158 #ifdef IBMSELECT
14159     ready_to_accept = (select(&sock, 1, 0, 0, 50) == 1);
14160 #else
14161 #ifdef BELLSELECT
14162     FD_ZERO(rfds);
14163     FD_SET(sock, rfds);
14164     ready_to_accept =
14165         ((select(128, rfds, NULL, NULL, 50) > 0) &&
14166           FD_ISSET(sock, rfds));
14167 #else
14168 /* Try this - what's the worst that can happen... */
14169
14170     tv.tv_sec  = tv.tv_usec = 0L;
14171     tv.tv_usec = 50;
14172     FD_ZERO(&rfds);
14173     FD_SET(sock, &rfds);
14174     ready_to_accept =
14175         ((select(FD_SETSIZE,
14176                   (fd_set *) &rfds, NULL, NULL, &tv) > 0) &&
14177           FD_ISSET(sock, &rfds));
14178 #endif /* BELLSELECT */
14179 #endif /* IBMSELECT */
14180 #endif /* BSDSELECT */
14181
14182     if ( !ready_to_accept )
14183         return(0);
14184
14185     if ((sock2 = accept(sock,(struct sockaddr *)&saddr,&saddrlen)) < 0) {
14186         int i = errno;                  /* save error code */
14187         debug(F101,"tcpsrv_open accept errno","",i);
14188         return(-1);
14189     }
14190
14191     /*
14192      * Now we have the open socket.  We must now find a channel to store
14193      * it in, and then notify the client.
14194      */
14195
14196     for ( channel=0;channel<MAXFWDX;channel++ ) {
14197         if ( TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[channel].fd == -1 )
14198             break;
14199     }
14200
14201     if ( channel == MAXFWDX ) {
14202 #ifdef TCPIPLIB
14203         socket_close(sock2);
14204 #else /* TCPIPLIB */
14205         close(sock2);
14206 #endif /* TCPIPLIB */
14207         return(-1);
14208     }
14209
14210     if ( fwdx_send_open(channel) < 0 ) {
14211 #ifdef TCPIPLIB
14212         socket_close(sock2);
14213 #else /* TCPIPLIB */
14214         close(sock2);
14215 #endif /* TCPIPLIB */
14216     }
14217
14218 #ifdef TCP_NODELAY
14219     setsockopt(sock2,IPPROTO_TCP,TCP_NODELAY,(char *)&on,sizeof(on));
14220 #endif /* TCP_NODELAY */
14221
14222     TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[channel].fd = sock2;
14223     TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[channel].id = channel;
14224     goto try_again;
14225
14226     return(0);  /* never reached */
14227 }
14228
14229 int
14230 fwdx_close_channel(channel) int channel; {
14231     int i,fd;
14232
14233     for ( i=0; i<MAXFWDX ; i++ ) {
14234         if (TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[i].id == channel)
14235             break;
14236     }
14237     if ( i == MAXFWDX )
14238         return(-1);
14239
14240     fd = TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[i].fd;
14241     TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[i].fd = -1;
14242     TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[i].id = -1;
14243     TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[i].need_to_send_xauth = 0;
14244
14245 #ifdef TCPIPLIB
14246     socket_close(fd);
14247 #else /* TCPIPLIB */
14248     close(fd);
14249 #endif /* TCPIPLIB */
14250     return(0);
14251 }
14252
14253 int
14254 fwdx_close_all() {
14255     int x,fd;
14256
14257     debug(F111,"fwdx_close_all()",
14258           "TELOPT_SB(TELOPT_FORWARD_X).forward_x.listen_socket",
14259           TELOPT_SB(TELOPT_FORWARD_X).forward_x.listen_socket);
14260
14261     if ( TELOPT_SB(TELOPT_FORWARD_X).forward_x.listen_socket != -1 ) {
14262 #ifdef TCPIPLIB
14263         socket_close(TELOPT_SB(TELOPT_FORWARD_X).forward_x.listen_socket);
14264 #else /* TCPIPLIB */
14265         close(TELOPT_SB(TELOPT_FORWARD_X).forward_x.listen_socket);
14266 #endif /* TCPIPLIB */
14267         TELOPT_SB(TELOPT_FORWARD_X).forward_x.listen_socket = -1;
14268     }
14269
14270     for (x = 0; x < MAXFWDX; x++) {
14271      if (TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].fd != -1) {
14272       fd = TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].fd;
14273       TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].fd = -1;
14274       TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].id = -1;
14275       TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].need_to_send_xauth = 0;
14276       TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].suspend = 0;
14277 #ifdef TCPIPLIB
14278       socket_close(fd);
14279 #else /* TCPIPLIB */
14280       close(fd);
14281 #endif /* TCPIPLIB */
14282      }
14283     }
14284     return(0);
14285 }
14286
14287 /* The following definitions are for Unix */
14288 #ifndef socket_write
14289 #define socket_write(f,s,n)    write(f,s,n)
14290 #endif /* socket_write */
14291 #ifndef socket_read
14292 #define socket_read(f,s,n)     read(f,s,n)
14293 #endif /* socket_read */
14294
14295 int
14296 fwdx_write_data_to_channel(channel, data, len)
14297     int channel; char * data; int len;
14298 {
14299     int sock, count, try=0, length = len, i;
14300
14301     if ( len <= 0 )
14302         return(0);
14303
14304     for ( i=0; i<MAXFWDX ; i++ ) {
14305         if (TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[i].id == channel)
14306             break;
14307     }
14308     if ( i == MAXFWDX ) {
14309         debug(F110,"fwdx_write_data_to_channel",
14310                "attempting to write to closed channel",0);
14311         return(-1);
14312     }
14313
14314     sock = TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[i].fd;
14315     debug(F111,"fwdx_write_data_to_channel","socket",sock);
14316     ckhexdump("fwdx_write_data_to_channel",data,len);
14317
14318   fwdx_write_data_to_channel_retry:
14319
14320     if ((count = socket_write(sock,data,len)) < 0) {
14321         int s_errno = socket_errno; /* maybe a function */
14322         debug(F101,"fwdx_write_data_to_channel socket_write error","",s_errno);
14323 #ifdef BETATEST
14324         printf("fwdx_write_data_to_channel error\r\n");
14325 #endif /* BETATEST */
14326 #ifdef OS2
14327         if (os2socketerror(s_errno) < 0)
14328             return(-2);
14329 #endif /* OS2 */
14330         return(-1);                 /* Call it an i/o error */
14331     }
14332     if (count < len) {
14333         debug(F111,"fwdx_write_data_to_channel socket_write",data,count);
14334         if (count > 0) {
14335             data += count;
14336             len -= count;
14337         }
14338         debug(F111,"fwdx_write_data_to_channel retry",data,len);
14339         if ( len > 0 )
14340             goto fwdx_write_data_to_channel_retry;
14341     }
14342
14343     debug(F111,"fwdx_write_data_to_channel complete",data,length);
14344     return(length); /* success - return total length */
14345 }
14346
14347 VOID
14348 fwdx_check_sockets(fd_set *ibits)
14349 {
14350     int x, sock, channel, bytes;
14351     static char buffer[32000];
14352
14353     debug(F100,"fwdx_check_sockets()","",0);
14354     if ( sstelnet && !TELOPT_ME(TELOPT_FORWARD_X) ||
14355          !sstelnet && !TELOPT_U(TELOPT_FORWARD_X)) {
14356         debug(F110,"fwdx_check_sockets()","TELOPT_FORWARD_X not negotiated",0);
14357         return;
14358     }
14359
14360     for (x = 0; x < MAXFWDX; x++) {
14361         if ( TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].fd == -1 ||
14362              TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].suspend )
14363             continue;
14364
14365         sock = TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].fd;
14366         if (FD_ISSET(sock, ibits))
14367         {
14368             channel = TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].id;
14369             debug(F111,"fwdx_check_sockets()","channel set",channel);
14370
14371             bytes = socket_read(sock, buffer, sizeof(buffer));
14372             if (bytes > 0)
14373                 fwdx_send_data_from_channel(channel, buffer, bytes);
14374             else if (bytes == 0) {
14375                 fwdx_close_channel(channel);
14376                 fwdx_send_close(channel);
14377             }
14378         }
14379     }
14380 }
14381
14382 int
14383 fwdx_init_fd_set(fd_set *ibits)
14384 {
14385     int x,set=0,cnt=0;
14386
14387     if ( sstelnet && !TELOPT_ME(TELOPT_FORWARD_X) ||
14388          !sstelnet && !TELOPT_U(TELOPT_FORWARD_X)) {
14389         debug(F110,"fwdx_init_fd_set()","TELOPT_FORWARD_X not negotiated",0);
14390         return(0);
14391     }
14392
14393     if (TELOPT_SB(TELOPT_FORWARD_X).forward_x.listen_socket != -1) {
14394         set++;
14395         FD_SET(TELOPT_SB(TELOPT_FORWARD_X).forward_x.listen_socket, ibits);
14396     }
14397     for (x = 0; x < MAXFWDX; x++) {
14398         if (TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].fd != -1) {
14399             cnt++;
14400             if (TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].suspend)
14401                 continue;
14402             set++;
14403             FD_SET(TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].fd, ibits);
14404         }
14405     }
14406     if (set + cnt == 0) {
14407         return(-1);
14408     } else {
14409         return(set);
14410     }
14411 }
14412
14413 #ifdef NT
14414 VOID
14415 fwdx_thread( VOID * dummy )
14416 {
14417     fd_set ifds;
14418     struct timeval tv;
14419     extern int priority;
14420     int n;
14421
14422     setint();
14423     SetThreadPrty(priority,isWin95() ? 3 : 11);
14424
14425     while ( !sstelnet && TELOPT_U(TELOPT_FORWARD_X) ||
14426             sstelnet && TELOPT_ME(TELOPT_FORWARD_X))
14427     {
14428         FD_ZERO(&ifds);
14429         n = fwdx_init_fd_set(&ifds);
14430         if (n > 0) {
14431             tv.tv_sec = 0;
14432             tv.tv_usec = 2500;
14433             if ( select(FD_SETSIZE, &ifds, NULL, NULL, &tv) > 0 )
14434                 fwdx_check_sockets(&ifds);
14435
14436         } else if (n < 0) {
14437             TELOPT_SB(TELOPT_FORWARD_X).forward_x.thread_started = 0;
14438             ckThreadEnd(NULL);
14439         } else {
14440             sleep(1);
14441         }
14442     }
14443 }
14444 #endif /* NT */
14445 #endif /* CK_FORWARD_X */
14446 #endif /* TNCODE */
14447 #endif /* NETCONN */