remove patch with docs shipped with 301
[ckermit.git] / ckcnet.c
1 char *cknetv = "Network support, 9.0.296, 16 Mar 2010";
2
3 /*  C K C N E T  --  Network support  */
4
5 /*
6   Copyright (C) 1985, 2010,
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 #include <errno.h>                      /* Already included above */
262 #endif /* I386IX */
263
264 #include <signal.h>                     /* Everybody needs this */
265
266 #ifdef ZILOG                            /* Zilog has different name for this */
267 #include <setret.h>
268 #else
269 #include <setjmp.h>
270 #endif /* ZILOG */
271
272 #endif /* WINTCP */
273
274 #ifdef datageneral                      /* Data General AOS/VS */
275 #include <:usr:include:vs_tcp_errno.h>
276 #include <:usr:include:sys:vs_tcp_types.h>
277 #ifdef SELECT
278 /*
279   NOTE: This can be compiled and linked OK with SELECT defined
280   but it doesn't work at all.  Anybody who cares and knows how
281   to fix it, feel free.
282 */
283 #include <:usr:include:sys:vs_tcp_time.h>
284 #endif /* SELECT */
285 #include <:usr:include:sys:socket.h>
286 #include <:usr:include:netinet:in.h>
287 #include <:usr:include:netdb.h>
288 #endif /* datageneral */
289
290 #ifndef socket_errno
291 #define socket_errno errno
292 #endif /* socket_errno */
293
294 #ifdef TNCODE
295 extern int tn_deb;
296 #endif /* TNCODE */
297
298 int tcp_rdns =                          /* Reverse DNS lookup */
299 #ifdef DEC_TCPIP_OLD
300     SET_OFF                             /* Doesn't seem to work in UCX */
301 #else
302      SET_AUTO
303 #endif /* DEC_TCPIP */
304       ;
305 #ifdef CK_DNS_SRV
306 int tcp_dns_srv = SET_OFF;
307 #endif /* CK_DNS_SRV */
308
309 _PROTOTYP( char * cmcvtdate, (char *, int) );
310
311 #ifdef RLOGCODE
312 _PROTOTYP( int rlog_ctrl, (CHAR *, int) );
313 _PROTOTYP( static int rlog_oob, (CHAR *, int) );
314 #ifndef TCPIPLIB
315 _PROTOTYP( static SIGTYP rlogoobh, ( int ) );
316 #endif /* TCPIPLIB */
317 _PROTOTYP( static int rlog_ini, (CHAR *, int,
318                                  struct sockaddr_in *,
319                                  struct sockaddr_in *) );
320 int rlog_mode = RL_COOKED;
321 int rlog_stopped = 0;
322 int rlog_inband = 0;
323 #endif /* RLOGCODE */
324
325 #ifndef NOICP
326 extern int doconx;                      /* CONNECT-class command active */
327 #endif /* NOICP */
328
329 #ifdef IBMX25
330 /* This variable should probably be generalised for true client/server
331  * support - ie: the fd of the listening server, accepted calls should
332  * be forked or at least handled via a second fd (for IBM's X.25 -
333  * ttyfd always holds the active fd - ie the server becomes inactive
334  * as long as a client is connected, and becomes active again when the
335  * connection is closed)
336  */
337 int x25serverfd = 0;            /* extern in ckcnet.h */
338 int x25seqno = 0;               /* Connection sequence number */
339 int x25lastmsg = -1;            /* A cheapskate's state table */
340
341 #define X25_CLOSED      0       /* Default state: no connection, no STREAM */
342 #define X25_SETUP       1       /* X.25 has been set up (no connection) */
343 #define X25_CONNECTED   2       /* X.25 connection has been established */
344 int x25_state = X25_CLOSED;     /* Default state */
345 #endif /* IBMX25 */
346
347 #ifndef DEBUG
348 #define deblog 0
349 #endif /* DEBUG */
350
351 #ifdef CK_NAWS                          /* Negotiate About Window Size */
352 #ifdef RLOGCODE
353 _PROTOTYP( int rlog_naws, (void) );
354 #endif /* RLOGCODE */
355 #endif /* CK_NAWS */
356
357 #ifdef OS2                              /* For terminal type name string */
358 #include "ckuusr.h"
359 #ifndef NT
360 #include <os2.h>
361 #undef COMMENT
362 #endif /* NT */
363 #include "ckocon.h"
364 extern int tt_type, max_tt;
365 extern struct tt_info_rec tt_info[];
366 extern char ttname[];
367 #else
368 #ifdef CK_AUTHENTICATION
369 #include "ckuusr.h"
370 #endif /* CK_AUTHENTICATION */
371 #endif /* OS2 */
372
373 #ifdef NT
374 extern int winsock_version;
375 #endif /* NT */
376
377 #ifdef CK_AUTHENTICATION
378 #include "ckuath.h"
379 #endif /* CK_AUTHENTICATION */
380
381 #include "ckcsig.h"
382
383 #ifndef OS2                             /* For timeout longjumps */
384 static ckjmpbuf njbuf;
385 #endif /* OS2 */
386
387 #define NAMECPYL 1024                   /* Local copy of hostname */
388 char namecopy[NAMECPYL];                /* Referenced by ckctel.c */
389 char namecopy2[NAMECPYL];               /* Referenced by ckctel.c */
390 #ifndef NOHTTP
391 char http_host_port[NAMECPYL];          /* orig host/port necessary for http */
392 char http_ip[20] = { '\0' };            /* ip address of host */
393 char http_port = 0;
394 int  http_ssl = 0;
395 char * http_agent = 0;
396 int  httpfd = -1;                       /* socket for http connections */
397 int  http_code = 0;
398 #define HTTPBUFLEN  1024
399 char http_reply_str[HTTPBUFLEN] = "";
400 #endif /* NOHTTP */
401
402 char ipaddr[20] = { '\0' };             /* Global copy of IP address */
403 unsigned long myxipaddr = 0L;           /* Ditto as a number */
404 #endif /* NETCONN */
405
406 char *tcp_address = NULL;               /* Preferred IP Address */
407 extern char uidbuf[];                   /* User ID buffer */
408 extern char pwbuf[];                    /* Password buffer */
409
410 #ifndef NOHTTP
411 char * tcp_http_proxy = NULL;           /* Name[:port] of http proxy server */
412 int    tcp_http_proxy_errno = 0;
413 char * tcp_http_proxy_user = NULL;
414 char * tcp_http_proxy_pwd  = NULL;
415 char * tcp_http_proxy_agent = NULL;
416 #define HTTPCPYL 1024
417 static char proxycopy[HTTPCPYL];
418 #endif /* NOHTTP */
419
420 #ifdef OS2
421 extern int tt_rows[], tt_cols[];
422 extern int tt_status[VNUM];
423 #else /* OS2 */
424 extern int tt_rows, tt_cols;            /* Everybody has this */
425 #endif /* OS2 */
426
427 extern int cmd_cols, cmd_rows;
428
429 #ifdef STREAMING                        /* Use blocking writes for streaming */
430 extern int streaming;
431 #endif /* STREAMING */
432
433 #ifdef NT
434 extern int WSASafeToCancel;
435 int win95selectbug = 0;                 /* For TCP/IP stacks whose select() */
436 /* always fails on write requests such as Cisco and Quarterdeck */
437 #define stricmp _stricmp
438 #endif /* NT */
439
440 #ifndef NOTCPOPTS
441
442 /* Skip all this if NOTCPOPTS specified. */
443
444 #ifdef SOL_SOCKET
445
446 #ifdef TCP_NODELAY
447 int tcp_nodelay = 0;                    /* Nagle algorithm TCP_NODELAY */
448 #endif /* TCP_NODELAY */
449
450 #ifdef SO_DONTROUTE
451 int tcp_dontroute = 0;
452 #endif /* SO_DONTROUTE */
453
454 #ifdef SO_LINGER
455 int tcp_linger  = 0;                    /* SO_LINGER */
456 int tcp_linger_tmo = 0;                 /* SO_LINGER timeout */
457 #endif /* SO_LINGER */
458
459 #ifdef HPUX                             /* But the data structures */
460 #ifndef HPUX8                           /* needed for linger are not */
461 #ifndef HPUX9                           /* defined in HP-UX versions */
462 #ifndef HPUX10                          /* prior to 8.00. */
463 #ifdef SO_LINGER
464 #undef SO_LINGER
465 #endif /* SO_LINGER */
466 #endif /* HPUX10 */
467 #endif /* HPUX9 */
468 #endif /* HPUX8 */
469 #endif /* HPUX */
470
471 #ifndef SO_OOBINLINE                    /* Hopefully only HP-UX 7.0 */
472 #define SO_OOBINLINE 0x0100
473 #endif /* SO_OOBINLINE */
474
475 #ifndef TCPSNDBUFSIZ
476 #ifdef VMS
477 #ifdef __alpha
478 #define TCPSNDBUFSIZ 16384
479 #endif /* __alpha */
480 #endif /* VMS */
481 #endif /* TCPSNDBUFSIZ */
482
483 #ifndef TCPSNDBUFSIZ
484 #define TCPSNDBUFSIZ -1
485 #endif /* TCPSNDBUFSIZ */
486
487 #ifdef SO_SNDBUF
488 int tcp_sendbuf = TCPSNDBUFSIZ;
489 #endif /* SO_SNDBUF */
490
491 #ifdef SO_RCVBUF
492 int tcp_recvbuf = -1;
493 #endif /* SO_RCVBUF */
494
495 #ifdef SO_KEEPALIVE
496 int tcp_keepalive = 1;
497 #endif /* SO_KEEPALIVE */
498
499 #endif /* SOL_SOCKET */
500 #endif /* NOTCPOPTS */
501
502 #ifndef NETCONN
503 /*
504   Network support not defined.
505   Dummy functions here in case #ifdef's forgotten elsewhere.
506 */
507 int                                     /* Open network connection */
508 netopen(name, lcl, nett) char *name; int *lcl, nett; {
509     return(-1);
510 }
511 int                                     /* Close network connection */
512 netclos() {
513     return(-1);
514 }
515 int                                     /* Check network input buffer */
516 nettchk() {
517     return(-1);
518 }
519 int                                     /* Flush network input buffer */
520 netflui() {
521     return(-1);
522 }
523 int                                     /* Send network BREAK */
524 netbreak() {
525     return(-1);
526 }
527 int                                     /* Input character from network */
528 netinc(timo) int timo; {
529     return(-1);
530 }
531 int                                     /* Output character to network */
532 #ifdef CK_ANSIC
533 nettoc(CHAR c)
534 #else
535 nettoc(c) CHAR c;
536 #endif /* CK_ANSIC */
537 /* nettoc */ {
538     return(-1);
539 }
540 int
541 nettol(s,n) CHAR *s; int n; {
542     return(-1);
543 }
544
545 #else /* NETCONN is defined (much of this module...) */
546
547 #ifdef NETLEBUF
548 VOID
549 le_init() {                             /* LocalEchoInit() */
550     int i;
551     for (i = 0; i < LEBUFSIZ; i++)
552       le_buf[i] = '\0';
553     le_start = 0;
554     le_end = 0;
555     le_data = 0;
556     tt_push_inited = 1;
557 }
558
559 VOID
560 le_clean() {                            /* LocalEchoCleanup() */
561     le_init();
562     return;
563 }
564
565 int
566 le_inbuf() {
567     int rc = 0;
568     if (le_start != le_end) {
569         rc = (le_end -
570               le_start +
571               LEBUFSIZ) % LEBUFSIZ;
572     }
573     return(rc);
574 }
575
576 int
577 #ifdef CK_ANSIC
578 le_putchar(CHAR ch)
579 #else
580 le_putchar(ch) CHAR ch;
581 #endif /* CK_ANSIC */
582 /* le_putchar */ {
583     if ((le_start - le_end + LEBUFSIZ)%LEBUFSIZ == 1) {
584         debug(F110,"le_putchar","buffer is full",0);
585         return(-1);
586     }
587     le_buf[le_end++] = ch;
588     if (le_end == LEBUFSIZ)
589       le_end = 0;
590     le_data = 1;
591     return(0);
592 }
593
594 int
595 #ifdef CK_ANSIC
596 le_puts(CHAR * s, int n)
597 #else
598 le_puts(s,n) CHAR * s; int n;
599 #endif /* CK_ANSIC */
600 /* le_puts */ {
601     int rc = 0;
602     int i = 0;
603     CHAR * p = (CHAR *)"le_puts";
604     ckhexdump(p,s,n);
605     for (i = 0; i < n; i++)
606       rc = le_putchar((char)s[i]);
607     debug(F101,"le_puts","",rc);
608     return(rc);
609 }
610
611 int
612 #ifdef CK_ANSIC
613 le_putstr(CHAR * s)
614 #else
615 le_putstr(s) CHAR * s;
616 #endif /* CK_ANSIC */
617 /* le_puts */ {
618     CHAR * p;
619     int rc = 0;
620     p = (CHAR *)"le_putstr";
621     ckhexdump(p,s,(int)strlen((char *)s));
622     for (p = s; *p && !rc; p++)
623       rc = le_putchar(*p);
624     return(rc);
625 }
626
627 int
628 #ifdef CK_ANSIC
629 le_getchar(CHAR * pch)
630 #else /* CK_ANSIC */
631 le_getchar(pch) CHAR * pch;
632 #endif /* CK_ANSIC */
633 /* le_gatchar */ {
634     int rc = 0;
635     if (le_start != le_end) {
636         *pch = le_buf[le_start];
637         le_buf[le_start] = 0;
638         le_start++;
639
640         if (le_start == LEBUFSIZ)
641           le_start = 0;
642
643         if (le_start == le_end) {
644             le_data = 0;
645         }
646         rc++;
647     } else {
648         *pch = 0;
649     }
650     return(rc);
651 }
652 #endif /* NETLEBUF */
653
654 #ifdef VMS
655 /*
656   In edit 190, we moved tn_ini() to be called from within netopen().
657   But tn_ini() calls ttol(), and ttol() checks to see if it's a net
658   connection, but the flag for that isn't set until after netopen()
659   is finished.  Since, in this module, we are always doing network
660   output anyway, we just call nettol() directly, instead of going thru
661   ttol().  Only needed for VMS, since UNIX, AOS/VS, and VOS can handle
662   net connections just like regular connections in ttol(), and OS/2
663   has a special routine for this.
664 */
665 #define ttol nettol
666 #endif /* VMS */
667
668 int tcpsrfd = -1;
669
670 #ifdef CK_KERBEROS
671
672 char * krb5_d_principal = NULL;         /* Default principal */
673 char * krb5_d_instance = NULL;          /* Default instance */
674 char * krb5_d_realm = NULL;             /* Default realm */
675 char * krb5_d_cc = NULL;                /* Default credentials cache */
676 char * krb5_d_srv   = NULL;             /* Default Service */
677 int    krb5_d_lifetime = 600;           /* Default lifetime (10 hours) */
678 int    krb5_d_forwardable = 0;          /* creds not forwardable */
679 int    krb5_d_proxiable = 0;            /* creds not proxiable */
680 int    krb5_d_renewable = 0;            /* creds not renewable (0 min) */
681 int    krb5_autoget = 1;                /* Autoget TGTs */
682 int    krb5_autodel = 0;                /* Auto delete TGTs */
683 int    krb5_d_getk4 = 0;                /* K5 Kinit gets K4 TGTs */
684 int    krb5_checkaddrs = 1;             /* Check TGT Addrs */
685 int    krb5_d_no_addresses = 0;         /* Do not include IP Addresses */
686 char * krb5_d_addrs[KRB5_NUM_OF_ADDRS+1]={NULL,NULL}; /* Addrs to include */
687 int    krb5_errno = 0;                  /* Last K5 errno */
688 char * krb5_errmsg = NULL;              /* Last K5 errmsg */
689 char * k5_keytab = NULL;
690
691 char * krb4_d_principal = NULL;         /* Default principal */
692 char * krb4_d_realm = NULL;             /* Default realm */
693 char * krb4_d_srv   = NULL;             /* Default Service */
694 int    krb4_d_lifetime = 600;           /* Default lifetime (10 hours) */
695 int    krb4_d_preauth = 1;              /* Use preauth requests */
696 char * krb4_d_instance = NULL;          /* Default instance */
697 int    krb4_autoget = 1;                /* Autoget TGTs */
698 int    krb4_autodel = 0;                /* Auto delete TGTs */
699 int    krb4_checkaddrs = 1;             /* Check TGT Addrs */
700 char * k4_keytab = NULL;
701
702 int    krb4_errno = 0;                  /* Last K4 errno */
703 char * krb4_errmsg = NULL;              /* Last K4 errmsg */
704
705 struct krb_op_data krb_op = {           /* Operational data structure */
706     0, NULL                             /* (version, cachefile) */
707 };
708
709 struct krb4_init_data krb4_init = {     /* Kerberos 4 INIT data structure */
710     0, NULL, NULL, NULL, NULL
711 };
712
713 struct krb5_init_data krb5_init = {     /* Kerberos 5 INIT data structure */
714     0, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, 0, 0, 0,
715     { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
716       NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
717     0
718 };
719
720 struct krb5_list_cred_data krb5_lc = {  /* List Credentials data structure */
721     0, 0, 0
722 };
723
724 int krb_action = -1;                    /* Kerberos action to perform */
725
726 #ifndef CK_AUTHENTICATION
727 char *
728 ck_krb4_getrealm() {
729     return("");
730 }
731 char *
732 ck_krb5_getrealm(cc) char * cc; {
733     return("");
734 }
735 char *
736 ck_krb4_getprincipal() {
737     return("");
738 }
739 char *
740 ck_krb5_getprincipal(cc) char * cc; {
741     return("");
742 }
743 #endif /* CK_AUTHENTICATION */
744
745 /*  I N I _ K E R B  --  Initialize Kerberos data  */
746
747 VOID
748 ini_kerb() {
749     int i;
750
751     krb_action = -1;                    /* No action specified */
752
753     krb_op.version = 0;                 /* Kerberos version (none) */
754     krb_op.cache = NULL;                /* Cache file (none) */
755
756 /* Kerberos 5 */
757
758     krb5_init.forwardable = krb5_d_forwardable; /* Init switch values... */
759     krb5_init.proxiable   = krb5_d_proxiable;
760     krb5_init.lifetime    = krb5_d_lifetime;
761     krb5_init.renew       = 0;
762     krb5_init.renewable   = krb5_d_renewable;
763     krb5_init.validate    = 0;
764     krb5_init.no_addresses = krb5_d_no_addresses;
765     krb5_init.getk4       = krb5_d_getk4;
766     if (krb5_init.postdate) {
767         free(krb5_init.postdate);
768         krb5_init.postdate = NULL;
769     }
770     if (krb5_init.service) {
771         free(krb5_init.service);
772         krb5_init.service = NULL;
773     }
774     if (!krb5_d_cc || !krb5_d_cc[0]) {  /* Set default cache */
775         char * p;
776         p = ck_krb5_get_cc_name();
777         makestr(&krb5_d_cc,(p && p[0]) ? p : NULL);
778     }
779     if (!krb5_d_realm || !krb5_d_realm[0]) { /* Set default realm */
780         char * p;
781         p = ck_krb5_getrealm(krb5_d_cc);
782         makestr(&krb5_d_realm,(p && p[0]) ? p : NULL);
783     }
784     makestr(&krb5_init.instance,krb5_d_instance);
785     makestr(&krb5_init.realm,krb5_d_realm); /* Set realm from default */
786     if (krb5_init.password) {
787         memset(krb5_init.password,0xFF,strlen(krb5_init.password));
788         free(krb5_init.password);
789         krb5_init.password = NULL;
790     }
791     if (!krb5_d_principal) {            /* Default principal */
792         /* a Null principal indicates the user should be prompted */
793         char * p = ck_krb5_getprincipal(krb5_d_cc);
794         if (!p || !(*p))
795           p = (char *)uidbuf;           /* Principal = user */
796                 makestr(&krb5_d_principal,(p && p[0]) ? p : NULL);
797     }
798     makestr(&krb5_init.principal,krb5_d_principal);
799     for (i = 0; i <= KRB5_NUM_OF_ADDRS; i++) {
800         if (krb5_init.addrs[i])
801           free(krb5_init.addrs[i]);
802         krb5_init.addrs[i] = NULL;
803     }
804     for (i = 0; i <= KRB5_NUM_OF_ADDRS && krb5_d_addrs[i]; i++) {
805         makestr(&krb5_init.addrs[i],krb5_d_addrs[i]);
806     }
807
808     /* Kerberos 4 */
809
810     krb4_init.lifetime = krb4_d_lifetime;
811     krb4_init.preauth  = krb4_d_preauth;
812     makestr(&krb4_init.instance,krb4_d_instance);
813     if (!krb4_d_realm || !krb4_d_realm[0]) {/* Set default realm */
814         char * p;
815         p = ck_krb4_getrealm();
816                 makestr(&krb4_d_realm,(p && p[0]) ? p : NULL);
817     }
818     makestr(&krb4_init.realm,krb4_d_realm);
819     if (krb4_init.password) {
820         memset(krb4_init.password,0xFF,strlen(krb4_init.password));
821         free(krb4_init.password);
822         krb4_init.password = NULL;
823     }
824     if (!krb4_d_principal) {            /* Default principal */
825         /* a Null principal indicates the user should be prompted */
826         char * p = ck_krb4_getprincipal();
827         if (!p || !(*p))
828           p = (char *)uidbuf;           /* Principal = user */
829         makestr(&(krb4_d_principal),(p && p[0]) ? p : NULL);
830     }
831     makestr(&(krb4_init.principal),krb4_d_principal);
832 }
833
834 /*  D O A U T H  --  AUTHENTICATE action routine  */
835
836 int
837 doauth(cx) int cx; {                    /* AUTHENTICATE action routine */
838     int rc = 0;                         /* Return code */
839
840 #ifdef CK_AUTHENTICATION
841 #ifdef OS2
842     if (!ck_security_loaddll())         /* Load various DLLs */
843       return(rc);
844 #endif /* OS2 */
845     if (krb_op.version == 4) {          /* Version = 4 */
846 #ifdef COMMENT
847         sho_auth(AUTHTYPE_KERBEROS_V4);
848 #endif /* COMMENT */
849         if (!ck_krb4_is_installed()) {
850             printf("?Kerberos 4 is not installed\n");
851             return(0);
852         }
853         switch (krb_action) {           /* Perform V4 functions */
854           case KRB_A_IN:                /* INIT */
855             rc |= !(ck_krb4_initTGT(&krb_op,&krb4_init) < 0);
856             break;
857           case KRB_A_DE:                /* DESTROY */
858             rc |= !(ck_krb4_destroy(&krb_op) < 0);
859             break;
860           case KRB_A_LC:                /* LIST-CREDENTIALS */
861             rc |= !(ck_krb4_list_creds(&krb_op) < 0);
862             break;
863         }
864     }
865     if (krb_op.version == 5) {          /* V5 functions */
866 #ifdef COMMENT
867         sho_auth(AUTHTYPE_KERBEROS_V5);
868 #endif /* COMMENT */
869         if (!ck_krb5_is_installed()) {
870             printf("?Kerberos 5 is not installed\n");
871             return(0);
872         }
873         switch (krb_action) {
874           case KRB_A_IN:                /* INIT */
875             rc |= !(ck_krb5_initTGT(&krb_op,&krb5_init,
876                                      krb5_init.getk4 ? &krb4_init : 0) < 0);
877             break;
878           case KRB_A_DE:                /* DESTROY */
879             rc |= !(ck_krb5_destroy(&krb_op) < 0);
880             break;
881           case KRB_A_LC:                /* LIST-CREDENTIALS */
882             if (krb_op.version == 0)
883               printf("\n");
884             rc |= !(ck_krb5_list_creds(&krb_op,&krb5_lc) < 0);
885             break;
886         }
887     }
888 #else
889 #ifndef NOICP
890 #ifndef NOSHOW
891     rc = sho_auth(0);                   /* Show all */
892 #endif /* NOSHOW */
893 #endif /* NOICP */
894 #endif /* CK_AUTHENTICATION */
895     return(rc);
896 }
897 #endif /* CK_KERBEROS */
898
899 #ifdef TCPSOCKET
900 #ifndef OS2
901 #ifndef NOLISTEN                        /* For incoming connections */
902
903 #ifndef INADDR_ANY
904 #define INADDR_ANY 0
905 #endif /* INADDR_ANY */
906
907 _PROTOTYP( int ttbufr, ( VOID ) );
908 _PROTOTYP( int tcpsrv_open, (char *, int *, int, int ) );
909
910 static unsigned short tcpsrv_port = 0;
911
912 #endif /* NOLISTEN */
913 #endif /* OS2 */
914
915 static char svcbuf[80];                 /* TCP service string */
916 static int svcnum = 0;                  /* TCP port number */
917
918 #endif /* TCPSOCKET */
919
920 /*
921   TCPIPLIB means use separate socket calls for i/o, while on UNIX the
922   normal file system calls are used for TCP/IP sockets too.
923   Means "DEC_TCPIP or MULTINET or WINTCP or OS2 or BEBOX" (see ckcnet.h),
924 */
925
926 #ifdef TCPIPLIB
927
928 /* For buffered network reads... */
929 /*
930   If the buffering code is written right, it shouldn't matter
931   how long this buffer is.
932 */
933 #ifdef OS2
934 #ifdef NT
935 #define TTIBUFL 64240                   /* 44 * 1460 (MSS) */
936 #else
937 #define TTIBUFL 32120                   /* 22 * 1460 (MSS) */
938 #endif /* NT */
939 #else /* OS2 */
940 #define TTIBUFL 8191                    /* Let's use 8K. */
941 #endif /* OS2 */
942
943 CHAR ttibuf[TTIBUFL+1];
944
945 /*
946   select() is used in preference to alarm()/signal(), but different systems
947   use different forms of select()...
948 */
949 #ifndef NOSELECT         /* Option to override BSDSELECT */
950 #ifdef BELLV10
951 /*
952   Note: Although BELLV10 does have TCP/IP support, and does use the unique
953   form of select() that is evident in this module (and in ckutio.c), it does
954   not have a sockets library and so we can't build Kermit TCP/IP support for
955   it.  For this, somebody would have to write TCP/IP streams code.
956 */
957 #define BELLSELECT
958 #ifndef FD_SETSIZE
959 #define FD_SETSIZE 128
960 #endif /* FD_SETSIZE */
961 #else
962 #ifdef WINTCP                           /* VMS with Wollongong WIN/TCP */
963 #ifndef OLD_TWG                         /* TWG 3.2 has only select(read) */
964 #define BSDSELECT
965 #endif /* OLD_TWG */
966 #else
967 #ifdef CMU_TCPIP                        /* LIBCMU can do select */
968 #define BSDSELECT
969 #else
970 #ifdef DEC_TCPIP
971 #define BSDSELECT
972 #else
973 #ifdef OS2                              /* OS/2 with TCP/IP */
974 #ifdef NT
975 #define BSDSELECT
976 #else /* NT */
977 #define IBMSELECT
978 #endif /* NT */
979 #endif /* OS2 */
980 #endif /* DEC_TCPIP */
981 #endif /* CMU_TCPIP */
982 #endif /* WINTCP */
983 #endif /* BELLV10 */
984 #endif /* NOSELECT */
985 /*
986   Others (TGV, TCPware, ...) use alarm()/signal().  The BSDSELECT case does not
987   compile at all; the IBMSELECT case compiles and links but crashes at runtime.
988   NOTE: If any of these can be converted to select(), they should be for two
989   reasons: (1) It's a lot faster; (2) certain sockets libraries do not like
990   their socket_read() calls to be interrupted; subsequent socket_read()'s tend
991   to fail with EBUSY.  This happened in the UCX case before it was converted
992   to use select().
993 */
994 #ifndef OS2
995 #ifndef VMS
996 static                                  /* These are used in CKVTIO.C */
997 #endif /* VMS */                        /* And in CKONET.C            */
998 #endif /* OS2 */
999 int
1000   ttibp = 0,
1001   ttibn = 0;
1002 /*
1003   Read bytes from network into internal buffer ttibuf[].
1004   To be called when input buffer is empty, i.e. when ttibn == 0.
1005
1006   Other network reading routines, like ttinc, ttinl, ttxin, should check the
1007   internal buffer first, and call this routine for a refill if necessary.
1008
1009   Returns -1 on error, 0 if nothing happens.  When data is read successfully,
1010   returns number of bytes read, and sets global ttibn to that number and
1011   ttibp (the buffer pointer) to zero.
1012 */
1013 _PROTOTYP( int ttbufr, ( VOID ) );
1014 int
1015 ttbufr() {                              /* TT Buffer Read */
1016     int count;
1017
1018     if (ttnet != NET_TCPB)              /* First make sure current net is */
1019       return(-1);                       /* TCP/IP; if not, do nothing. */
1020
1021 #ifdef OS2
1022     RequestTCPIPMutex(SEM_INDEFINITE_WAIT);
1023 #endif /* OS2 */
1024
1025     if (ttibn > 0) {                    /* Our internal buffer is not empty, */
1026 #ifdef OS2
1027         ReleaseTCPIPMutex();
1028 #endif /* OS2 */
1029         return(ttibn);                  /* so keep using it. */
1030     }
1031
1032     if (ttyfd == -1) {                  /* No connection, error */
1033 #ifdef OS2
1034         ReleaseTCPIPMutex();
1035 #endif /* OS2 */
1036         return(-2);
1037     }
1038
1039     ttibp = 0;                          /* Else reset pointer to beginning */
1040
1041 #ifdef WINTCP
1042     count = 512;                        /* This works for WIN/TCP */
1043 #else
1044 #ifdef DEC_TCPIP
1045     count = 512;                        /* UCX */
1046 #else
1047 #ifdef OS2
1048     count = TTIBUFL;
1049 #else                                   /* Multinet, etc. */
1050     count = ttchk();                    /* Check network input buffer, */
1051     if (ttibn > 0) {                    /* which can put a char there! */
1052         debug(F111,"ttbufr","ttchk() returns",count);
1053 #ifdef OS2
1054         ReleaseTCPIPMutex();
1055 #endif /* OS2 */
1056         return(ttibn);
1057     }
1058     if (count < 0) {                     /* Read error - connection closed */
1059 #ifdef OS2
1060         ReleaseTCPIPMutex();
1061 #endif /* OS2 */
1062         return(-2);
1063     }
1064     else if (count > TTIBUFL)           /* Too many to read */
1065       count = TTIBUFL;
1066     else if (count == 0)                /* None, so force blocking read */
1067       count = 1;
1068 #endif /* OS2 */
1069 #endif /* DEC_TCPIP */
1070 #endif /* WINTCP */
1071     debug(F101,"ttbufr count 1","",count);
1072
1073 #ifdef CK_SSL
1074     if (ssl_active_flag || tls_active_flag) {
1075         int error;
1076       ssl_read:
1077         if (ssl_active_flag)
1078           count = SSL_read(ssl_con, ttibuf, count);
1079         else
1080           count = SSL_read(tls_con, ttibuf, count);
1081         error = SSL_get_error(ssl_active_flag?ssl_con:tls_con,count);
1082         switch (error) {
1083           case SSL_ERROR_NONE:
1084             debug(F111,"ttbufr SSL_ERROR_NONE","count",count);
1085             if (count > 0) {
1086                 ttibp = 0;              /* Reset buffer pointer. */
1087                 ttibn = count;
1088 #ifdef OS2
1089                 ReleaseTCPIPMutex();
1090 #endif /* OS2 */
1091                 return(ttibn);          /* Return buffer count. */
1092             } else if (count < 0) {
1093 #ifdef OS2
1094                 ReleaseTCPIPMutex();
1095 #endif /* OS2 */
1096                 return(-1);
1097             } else {
1098                 netclos();
1099 #ifdef OS2
1100                 ReleaseTCPIPMutex();
1101 #endif /* OS2 */
1102                 return(-2);
1103             }
1104           case SSL_ERROR_WANT_WRITE:
1105             debug(F100,"ttbufr SSL_ERROR_WANT_WRITE","",0);
1106 #ifdef OS2
1107               ReleaseTCPIPMutex();
1108 #endif /* OS2 */
1109             return(-1);
1110           case SSL_ERROR_WANT_READ:
1111             debug(F100,"ttbufr SSL_ERROR_WANT_READ","",0);
1112 #ifdef OS2
1113             ReleaseTCPIPMutex();
1114 #endif /* OS2 */
1115             return(-1);
1116           case SSL_ERROR_SYSCALL:
1117               if ( count == 0 ) { /* EOF */
1118                   netclos();
1119 #ifdef OS2
1120                   ReleaseTCPIPMutex();
1121 #endif /* OS2 */
1122                   return(-2);
1123               } else {
1124                   int rc = -1;
1125 #ifdef NT
1126                   int gle = GetLastError();
1127                   debug(F111,"ttbufr SSL_ERROR_SYSCALL",
1128                          "GetLastError()",gle);
1129                   rc = os2socketerror(gle);
1130                   if (rc == -1)
1131                       rc = -2;
1132                   else if ( rc == -2 )
1133                       rc = -1;
1134 #endif /* NT */
1135 #ifdef OS2
1136                   ReleaseTCPIPMutex();
1137 #endif /* OS2 */
1138                   return(rc);
1139               }
1140           case SSL_ERROR_WANT_X509_LOOKUP:
1141             debug(F100,"ttbufr SSL_ERROR_WANT_X509_LOOKUP","",0);
1142             netclos();
1143 #ifdef OS2
1144               ReleaseTCPIPMutex();
1145 #endif /* OS2 */
1146             return(-2);
1147           case SSL_ERROR_SSL:
1148               if (bio_err!=NULL) {
1149                   int len;
1150                   extern char ssl_err[];
1151                   BIO_printf(bio_err,"ttbufr SSL_ERROR_SSL\n");
1152                   ERR_print_errors(bio_err);
1153                   len = BIO_read(bio_err,ssl_err,SSL_ERR_BFSZ);
1154                   ssl_err[len < SSL_ERR_BFSZ ? len : SSL_ERR_BFSZ] = '\0';
1155                   debug(F110,"ttbufr SSL_ERROR_SSL",ssl_err,0);
1156                   if (ssl_debug_flag)                  
1157                       printf(ssl_err);
1158               } else if (ssl_debug_flag) {
1159                   debug(F100,"ttbufr SSL_ERROR_SSL","",0);
1160                   fflush(stderr);
1161                   fprintf(stderr,"ttbufr SSL_ERROR_SSL\n");
1162                   ERR_print_errors_fp(stderr);
1163               }
1164 #ifdef COMMENT
1165               netclos();
1166 #endif /* COMMENT */
1167 #ifdef OS2
1168               ReleaseTCPIPMutex();
1169 #endif /* OS2 */
1170             return(-2);
1171           case SSL_ERROR_ZERO_RETURN:
1172             debug(F100,"ttbufr SSL_ERROR_ZERO_RETURN","",0);
1173             netclos();
1174 #ifdef OS2
1175               ReleaseTCPIPMutex();
1176 #endif /* OS2 */
1177             return(-2);
1178           default:
1179               debug(F100,"ttbufr SSL_ERROR_?????","",0);
1180               netclos();
1181 #ifdef OS2
1182               ReleaseTCPIPMutex();
1183 #endif /* OS2 */
1184               return(-2);
1185           }
1186     }
1187 #endif /* CK_SSL */
1188
1189 #ifdef COMMENT
1190 /*
1191  This is for nonblocking reads, which we don't do any more.  This code didn't
1192  work anyway, in the sense that a broken connection was never sensed.
1193 */
1194     if ((count = socket_read(ttyfd,&ttibuf[ttibp+ttibn],count)) < 1) {
1195         if (count == -1 && socket_errno == EWOULDBLOCK) {
1196             debug(F100,"ttbufr finds nothing","",0);
1197 #ifdef OS2
1198             ReleaseTCPIPMutex();
1199 #endif /* OS2 */
1200             return(0);
1201         } else {
1202             debug(F101,"ttbufr socket_read error","",socket_errno);
1203 #ifdef OS2
1204             ReleaseTCPIPMutex();
1205 #endif /* OS2 */
1206             return(-1);
1207         }
1208
1209     } else if (count == 0) {
1210         debug(F100,"ttbufr socket eof","",0);
1211 #ifdef OS2
1212         ReleaseTCPIPMutex();
1213 #endif /* OS2 */
1214         return(-1);
1215     }
1216 #else /* COMMENT */
1217
1218 /* This is for blocking reads */
1219
1220 #ifndef VMS
1221 #ifdef SO_OOBINLINE
1222     {
1223         int outofband = 0;
1224 #ifdef BELLSELECT
1225         if (select(128, NULL, NULL, efds, 0) > 0 && FD_ISSET(ttyfd, efds))
1226           outofband = 1;
1227 #else
1228 #ifdef BSDSELECT
1229         fd_set efds;
1230         struct timeval tv;
1231         FD_ZERO(&efds);
1232         FD_SET(ttyfd, &efds);
1233         tv.tv_sec  = tv.tv_usec = 0L;
1234         debug(F100,"Out-of-Band BSDSELECT","",0);
1235 #ifdef NT
1236         WSASafeToCancel = 1;
1237 #endif /* NT */
1238         if (select(FD_SETSIZE, NULL, NULL, &efds, &tv) > 0 &&
1239             FD_ISSET(ttyfd, &efds))
1240           outofband = 1;
1241 #ifdef NT
1242         WSASafeToCancel = 0;
1243 #endif /* NT */
1244 #else /* !BSDSELECT */
1245 #ifdef IBMSELECT
1246 /* Is used by OS/2 ... */
1247 /* ... and it came in handy!  For our TCP/IP layer, it avoids all the fd_set */
1248 /* and timeval stuff since this is the only place where it is used. */
1249         int socket = ttyfd;
1250         debug(F100,"Out-of-Band IBMSELECT","",0);
1251         if ((select(&socket, 0, 0, 1, 0L) == 1) && (socket == ttyfd))
1252           outofband = 1;
1253 #else /* !IBMSELECT */
1254 /*
1255   If we can't use select(), then we use the regular alarm()/signal()
1256   timeout mechanism.
1257 */
1258       debug(F101,"Out-of-Band data not supported","",0);
1259       outofband = 0;
1260
1261 #endif /* IBMSELECT */
1262 #endif /* BSDSELECT */
1263 #endif /* BELLSELECT */
1264       if (outofband) {
1265          /* Get the Urgent Data */
1266          /* if OOBINLINE is disabled this should be only a single byte      */
1267          /* MS Winsock has a bug in Windows 95.  Extra bytes are delivered  */
1268          /* That were never sent.                                           */
1269 #ifdef OS2
1270           RequestTCPIPMutex(SEM_INDEFINITE_WAIT);
1271 #endif /* OS2 */
1272           count = socket_recv(ttyfd,&ttibuf[ttibp+ttibn],count,MSG_OOB);
1273 #ifdef OS2
1274           ReleaseTCPIPMutex();
1275 #endif /* OS2 */
1276           if (count <= 0) {
1277               int s_errno = socket_errno;
1278               debug(F101, "ttbufr socket_recv MSG_OOB","",count);
1279               debug(F101, "ttbufr socket_errno","",s_errno);
1280 #ifdef OS2ONLY
1281               if (count < 0 && (s_errno == 0 || s_errno == 23)) {
1282                   /* These appear in OS/2 - don't know why   */
1283                   /* ignore it and read as normal data       */
1284                   /* and break, then we will attempt to read */
1285                   /* the port using normal read() techniques */
1286                   debug(F100,"ttbufr handing as in-band data","",0);
1287                   count = 1;
1288               } else {
1289                   netclos();                    /* *** *** */
1290 #ifdef OS2
1291                   ReleaseTCPIPMutex();
1292 #endif /* OS2 */
1293                   return(-2);
1294               }
1295 #else /* OS2ONLY */
1296               netclos();                        /* *** *** */
1297 #ifdef OS2
1298               ReleaseTCPIPMutex();
1299 #endif /* OS2 */
1300               return(-2);
1301 #endif /* OS2ONLY */
1302           } else {                      /* we got out-of-band data */
1303               ckhexdump("ttbufr out-of-band chars",&ttibuf[ttibp+ttibn],count);
1304 #ifdef BETADEBUG
1305               bleep(BP_NOTE);
1306 #endif /* BETADEBUG */
1307 #ifdef RLOGCODE                         /* blah */
1308               if (ttnproto == NP_RLOGIN  ||
1309                   ttnproto == NP_K4LOGIN || ttnproto == NP_EK4LOGIN ||
1310                   ((ttnproto == NP_K5LOGIN || ttnproto == NP_EK5LOGIN) && 
1311                   !rlog_inband)
1312                    )
1313               {
1314                   /*
1315                     When urgent data is read with MSG_OOB and not OOBINLINE
1316                     then urgent data and normal data are not mixed.  So
1317                     treat the entire buffer as urgent data.
1318                   */
1319                   rlog_oob(&ttibuf[ttibp+ttibn], count);
1320 #ifdef OS2
1321                   ReleaseTCPIPMutex();
1322 #endif /* OS2 */
1323                   return ttbufr();
1324               } else
1325 #endif /* RLOGCODE */ /* blah */
1326 #ifdef COMMENT
1327             /*
1328                I haven't written this yet, nor do I know what it should do
1329              */
1330                 if (ttnproto == NP_TELNET) {
1331                     tn_oob();
1332 #ifdef OS2
1333                     ReleaseTCPIPMutex();
1334 #endif /* OS2 */
1335                     return 0;
1336               } else
1337 #endif /* COMMENT */
1338               {
1339                   /* For any protocols we don't have a special out-of-band  */
1340                   /* handler for, just put the bytes in the normal buffer   */
1341                   /* and return                                             */
1342
1343                   ttibp += 0;       /* Reset buffer pointer. */
1344                   ttibn += count;
1345 #ifdef DEBUG
1346                   /* Got some bytes. */
1347                   debug(F101,"ttbufr count 2","",count);
1348                   if (count > 0)
1349                       ttibuf[ttibp+ttibn] = '\0';
1350                   debug(F111,"ttbufr ttibuf",ttibuf,ttibp);
1351 #endif /* DEBUG */
1352 #ifdef OS2
1353                   ReleaseTCPIPMutex();
1354 #endif /* OS2 */
1355                   return(ttibn);    /* Return buffer count. */
1356               }
1357           }
1358       }
1359     }
1360 #endif /* SO_OOBINLINE */
1361 #endif /* VMS */
1362
1363     count = socket_read(ttyfd,&ttibuf[ttibp+ttibn],count);
1364     if (count <= 0) {
1365         int s_errno = socket_errno;
1366         debug(F101,"ttbufr socket_read","",count);
1367         debug(F101,"ttbufr socket_errno","",s_errno);
1368 #ifdef OS2
1369         if (count == 0 || os2socketerror(s_errno) < 0) {
1370             netclos();
1371             ReleaseTCPIPMutex();
1372             return(-2);
1373         }
1374         ReleaseTCPIPMutex();
1375         return(-1);
1376 #else /* OS2 */
1377         netclos();                      /* *** *** */
1378         return(-2);
1379 #endif /* OS2 */
1380     }
1381 #endif /* COMMENT */ /* (blocking vs nonblock reads...) */
1382     else {
1383         ttibp = 0;                      /* Reset buffer pointer. */
1384         ttibn += count;
1385 #ifdef DEBUG
1386         debug(F101,"ttbufr count 2","",count); /* Got some bytes. */
1387         if (count > 0)
1388           ttibuf[ttibp+ttibn] = '\0';
1389         debug(F111,"ttbufr ttibuf",&ttibuf[ttibp],ttibn);
1390 #endif /* DEBUG */
1391
1392 #ifdef OS2
1393         ReleaseTCPIPMutex();
1394 #endif /* OS2 */
1395         return(ttibn);                  /* Return buffer count. */
1396     }
1397 }
1398 #endif /* TCPIPLIB */
1399
1400 #ifndef IBMSELECT
1401 #ifndef BELLSELECT
1402 #ifndef BSDSELECT               /* Non-TCPIPLIB case */
1403 #ifdef SELECT
1404 #define BSDSELECT
1405 #endif /* SELECT */
1406 #endif /* BSDSELECT */
1407 #endif /* BELLSELECT */
1408 #endif /* IBMSELECT */
1409
1410 #define TELNET_PORT 23          /* Should do lookup, but it won't change */
1411 #define RLOGIN_PORT 513
1412 #define KERMIT_PORT 1649
1413 #define KLOGIN_PORT 543
1414 #define EKLOGIN_PORT 2105
1415
1416 #ifndef NONET
1417 /*
1418   C-Kermit network open/close functions for BSD-sockets.
1419   Much of this code shared by SunLink X.25, which also uses the socket library.
1420 */
1421
1422 /*  N E T O P N  --  Open a network connection.  */
1423 /*
1424   Call with:
1425     name of host (or host:service),
1426     lcl - local-mode flag to be set if this function succeeds,
1427     network type - value defined in ckunet.h.
1428 */
1429 #ifdef TCPSOCKET
1430 struct hostent *
1431 #ifdef CK_ANSIC
1432 ck_copyhostent(struct hostent * h)
1433 #else /* CK_ANSIC */
1434 ck_copyhostent(h) struct hostent * h;
1435 #endif /* CK_ANSIC */
1436 {
1437     /*
1438      *  The hostent structure is dynamic in nature.
1439      *  struct  hostent {
1440      *  char    * h_name;
1441      *  char    * * h_aliases;
1442      *  short   h_addrtype;
1443      *  short   h_length;
1444      *  char    * * h_addr_list;
1445      *  #define h_addr  h_addr_list[0]
1446      */
1447 #define HOSTENTCNT 5
1448     static struct hostent hosts[HOSTENTCNT] = {{NULL,NULL,0,0,NULL},
1449                                                {NULL,NULL,0,0,NULL},
1450                                                {NULL,NULL,0,0,NULL},
1451                                                {NULL,NULL,0,0,NULL},
1452                                                {NULL,NULL,0,0,NULL}};
1453     static int    next = 0;
1454     int    i,cnt;
1455     char ** pp;
1456
1457     if ( h == NULL )
1458         return(NULL);
1459
1460     if (next == HOSTENTCNT)
1461         next = 0;
1462
1463     if ( hosts[next].h_name ) {
1464         free(hosts[next].h_name);
1465         hosts[next].h_name = NULL;
1466     }
1467     if ( hosts[next].h_aliases ) {
1468         pp = hosts[next].h_aliases;
1469         while ( *pp ) {
1470             free(*pp);
1471             pp++;
1472         }
1473         free(hosts[next].h_aliases);
1474     }
1475 #ifdef HADDRLIST
1476     if ( hosts[next].h_addr_list ) {
1477         pp = hosts[next].h_addr_list;
1478         while ( *pp ) {
1479             free(*pp);
1480             pp++;
1481         }
1482         free(hosts[next].h_addr_list);
1483     }
1484 #endif /* HADDRLIST */
1485
1486     makestr(&hosts[next].h_name,h->h_name);
1487     if (h->h_aliases) {
1488         for ( cnt=0,pp=h->h_aliases; pp && *pp; pp++,cnt++) ;
1489         /* The following can give warnings in non-ANSI builds */
1490         hosts[next].h_aliases = (char **) malloc(sizeof(char *) * (cnt+1));
1491         for ( i=0; i<cnt; i++) {
1492             hosts[next].h_aliases[i] = NULL;
1493             makestr(&hosts[next].h_aliases[i],h->h_aliases[i]);
1494         }
1495         hosts[next].h_aliases[i] = NULL;
1496     } else
1497         hosts[next].h_aliases = NULL;
1498
1499     hosts[next].h_addrtype = h->h_addrtype;
1500     hosts[next].h_length = h->h_length;
1501
1502 #ifdef HADDRLIST
1503 #ifdef h_addr
1504     if (h->h_addr_list) {
1505         for ( cnt=0,pp=h->h_addr_list; pp && *pp; pp++,cnt++) ;
1506         /* The following can give warnings non-ANSI builds */
1507         hosts[next].h_addr_list = (char **) malloc(sizeof(char *) * (cnt+1));
1508         for ( i=0; i<cnt; i++) {
1509             hosts[next].h_addr_list[i] = malloc(h->h_length);
1510             bcopy(h->h_addr_list[i],hosts[next].h_addr_list[i],h->h_length);
1511         }
1512         hosts[next].h_addr_list[i] = NULL;
1513     } else
1514         hosts[next].h_addr_list = NULL;
1515 #else
1516     bcopy(h->h_addr, &hosts[next].h_addr, h->h_length);
1517 #endif /* h_addr */
1518 #else /* HADDRLIST */
1519     bcopy(h->h_addr, &hosts[next].h_addr, h->h_length);
1520 #endif /* HADDRLIST */
1521
1522     return(&hosts[next++]);
1523 }
1524
1525 #ifdef EXCELAN
1526 /*
1527   Most other BSD sockets implementations define these in header files
1528   and libraries.
1529 */
1530 struct servent {
1531     unsigned short s_port;
1532 };
1533
1534 struct hostent {
1535     short h_addrtype;
1536     struct in_addr h_addr;
1537     int h_length;
1538 };
1539
1540 struct servent *
1541 getservbyname(service, connection) char *service,*connection; {
1542     static struct servent servrec;
1543     int port;
1544
1545     port = 0;
1546     if (strcmp(service, "telnet") == 0) port = 23;
1547     else if (strcmp(service, "smtp") == 0) port = 25;
1548     else port = atoi(service);
1549
1550     debug(F101,"getservbyname return port ","",port);
1551
1552     if (port > 0) {
1553         servrec.s_port = htons(port);
1554         return(&servrec);
1555     }
1556     return((struct servent *) NULL);
1557 }
1558
1559 struct hostent *
1560 gethostbyname(hostname) char *hostname; {
1561     return((struct hostent *) NULL);
1562 }
1563
1564 unsigned long
1565 inet_addr(name) char *name; {
1566     unsigned long addr;
1567
1568     addr = rhost(&name);
1569     debug(F111,"inet_addr ",name,(int)addr);
1570     return(addr);
1571 }
1572
1573 char *
1574 inet_ntoa(in) struct in_addr in; {
1575     static char name[80];
1576     ckmakxmsg(name, ckuitoa(in.s_net),".",ckuitoa(in.s_host),".",
1577                ckuitoa(in.s_lh),".", ckuitoa(in.s_impno));
1578     return(name);
1579 }
1580 #else
1581 #ifdef DEC_TCPIP                        /* UCX */
1582
1583 int ucx_port_bug = 0;                   /* Explained below */
1584
1585 #ifdef OLDIP                            /* Very old VAXC or GCC */
1586 /*
1587   Note that my oldest VAX C (V3.1-051) does not need (or want) OLDIP,
1588   hence the "Very old" in the comment - SMS, 2010/03/15.
1589 */
1590 #define getservbyname my_getservbyname
1591
1592 #ifdef CK_ANSIC
1593 globalref int (*C$$GA_UCX_GETSERVBYNAME)();
1594 extern void C$$TRANSLATE();
1595 extern void C$$SOCK_TRANSLATE();
1596 #else
1597 globalref int (*C$$GA_UCX_GETSERVBYNAME)();
1598 extern VOID C$$TRANSLATE();
1599 extern VOID C$$SOCK_TRANSLATE();
1600 #endif /* CK_ANSIC */
1601
1602 struct servent *
1603 my_getservbyname (service, proto) char *service, *proto; {
1604     static struct servent sent;
1605     struct iosb {
1606         union {
1607             unsigned long status;
1608             unsigned short st[2];
1609         } sb;
1610         unsigned long spare;
1611     } s;
1612     struct {
1613         struct iosb *s;
1614         char *serv;
1615         char *prot;
1616     } par;
1617     unsigned long e;
1618     char sbuf[30], pbuf[30];
1619     char *p;
1620
1621     debug(F111,"UCX getservbyname",service,(int)C$$GA_UCX_GETSERVBYNAME);
1622
1623     p = sbuf;
1624     ckstrncpy(p, service, 29);
1625     while (*p = toupper(*p), *p++) {}
1626     p = pbuf;
1627     ckstrncpy(p, proto, 29);
1628     while (*p = toupper(*p), *p++) {}
1629
1630     par.s = &s;
1631
1632     par.serv = "";
1633     par.prot = "";
1634     /* reset file pointer or something like that!?!? */
1635     e = (*C$$GA_UCX_GETSERVBYNAME)(&par, &sent, par.s);
1636     par.serv = sbuf;
1637     par.prot = pbuf;            /* that is don't care */
1638     e = (*C$$GA_UCX_GETSERVBYNAME)(&par, &sent, par.s);
1639     if ((long)e == -1L)
1640       return NULL;
1641     if ((e & 1) == 0L) {
1642         C$$TRANSLATE(e);
1643         return NULL;
1644     }
1645     if ((s.sb.st[0] & 1) == 0) {
1646         C$$SOCK_TRANSLATE(&s.sb.st[0]);
1647         return NULL;
1648     }
1649 /*
1650   sent.s_port is supposed to be returned by UCX in network byte order.
1651   However, UCX 2.0 through 2.0C did not do this; 2.0D and later do it.
1652   But there is no way of knowing which UCX version, so we have a user-settable
1653   runtime variable.  Note: UCX 2.0 was only for the VAX.
1654 */
1655     debug(F101,"UCX getservbyname port","",sent.s_port);
1656     debug(F101,"UCX getservbyname ntohs(port)","",ntohs(sent.s_port));
1657     if (ucx_port_bug) {
1658         sent.s_port = htons(sent.s_port);
1659         debug(F100,"UCX-PORT-BUG ON: swapping bytes","",0);
1660         debug(F101,"UCX swapped port","",sent.s_port);
1661         debug(F101,"UCX swapped ntohs(port)","",ntohs(sent.s_port));
1662     }
1663     return &sent;
1664 }
1665 #endif /* def OLDIP */
1666 #endif /* DEC_TCPIP */
1667 #endif /* EXCELAN */
1668
1669 int
1670 gettcpport() {
1671     return(svcnum);
1672 }
1673
1674 #endif /* TCPSOCKET */
1675
1676 #ifndef NOTCPOPTS
1677 #ifndef datageneral
1678 int
1679 ck_linger(sock, onoff, timo) int sock; int onoff; int timo; {
1680 /*
1681   The following, from William Bader, turns off the socket linger parameter,
1682   which makes a close() block until all data is sent.  "I don't think that
1683   disabling linger can ever cause kermit to lose data, but you telnet to a
1684   flaky server (or to our modem server when the modem is in use), disabling
1685   linger prevents kermit from hanging on the close if you try to exit."
1686
1687   Modified by Jeff Altman to be generally useful.
1688 */
1689 #ifdef SOL_SOCKET
1690 #ifdef SO_LINGER
1691     struct linger set_linger_opt;
1692     struct linger get_linger_opt;
1693     SOCKOPT_T x;
1694
1695 #ifdef IKSD
1696     if (!inserver)
1697 #endif /* IKSD */
1698       if (sock == -1 ||
1699         nettype != NET_TCPA && nettype != NET_TCPB &&
1700         nettype != NET_SSH || ttmdm >= 0) {
1701         tcp_linger = onoff;
1702         tcp_linger_tmo = timo;
1703         return(1);
1704     }
1705     x = sizeof(get_linger_opt);
1706     if (getsockopt(sock, SOL_SOCKET, SO_LINGER,
1707                     (char *)&get_linger_opt, &x)) {
1708         debug(F111,"TCP ck_linger can't get SO_LINGER",ck_errstr(),errno);
1709     } else if (x != sizeof(get_linger_opt)) {
1710 #ifdef OS2
1711         struct _linger16 {
1712             short s_linger;
1713             short s_onoff;
1714         } get_linger_opt16, set_linger_opt16;
1715         if ( x == sizeof(get_linger_opt16) ) {
1716             debug(F111,"TCP setlinger warning: SO_LINGER","len is 16-bit",x);
1717             if (getsockopt(sock,
1718                            SOL_SOCKET, SO_LINGER,
1719                            (char *)&get_linger_opt16, &x)
1720                 ) {
1721                 debug(F111,
1722                       "TCP ck_linger can't get SO_LINGER",ck_errstr(),errno);
1723             } else if (get_linger_opt16.s_onoff != onoff ||
1724                        get_linger_opt16.s_linger != timo)
1725             {
1726                 set_linger_opt16.s_onoff  = onoff;
1727                 set_linger_opt16.s_linger = timo;
1728                 if (setsockopt(sock,
1729                                SOL_SOCKET,
1730                                SO_LINGER,
1731                                (char *)&set_linger_opt16,
1732                                sizeof(set_linger_opt16))
1733                     ) {
1734                     debug(F111,
1735                           "TCP ck_linger can't set SO_LINGER",
1736                           ck_errstr(),
1737                           errno
1738                           );
1739                     tcp_linger = get_linger_opt16.s_onoff;
1740                     tcp_linger_tmo = get_linger_opt16.s_linger;
1741                 } else {
1742                     debug(F101,
1743                           "TCP ck_linger new SO_LINGER","",
1744                           set_linger_opt16.s_onoff);
1745                     tcp_linger = set_linger_opt16.s_onoff;
1746                     tcp_linger_tmo = set_linger_opt16.s_linger;
1747                     return 1;
1748                 }
1749             } else {
1750                 debug(F101,"TCP ck_linger SO_LINGER unchanged","",
1751                        get_linger_opt16.s_onoff);
1752                 tcp_linger = get_linger_opt16.s_onoff;
1753                 tcp_linger_tmo = get_linger_opt16.s_linger;
1754                 return 1;
1755             }
1756             return(0);
1757         }
1758 #endif /* OS2 */
1759         debug(F111,"TCP ck_linger error: SO_LINGER","len",x);
1760         debug(F111,"TCP ck_linger SO_LINGER",
1761               "expected len",sizeof(get_linger_opt));
1762         debug(F111,"TCP ck_linger SO_LINGER","linger_opt.l_onoff",
1763               get_linger_opt.l_onoff);
1764         debug(F111,"TCP linger SO_LINGER","linger_opt.l_linger",
1765                get_linger_opt.l_linger);
1766     } else if (get_linger_opt.l_onoff != onoff ||
1767                get_linger_opt.l_linger != timo) {
1768         set_linger_opt.l_onoff  = onoff;
1769         set_linger_opt.l_linger = timo;
1770         if (setsockopt(sock,
1771                        SOL_SOCKET,
1772                        SO_LINGER,
1773                        (char *)&set_linger_opt,
1774                        sizeof(set_linger_opt))) {
1775             debug(F111,"TCP ck_linger can't set SO_LINGER",ck_errstr(),errno);
1776             tcp_linger = get_linger_opt.l_onoff;
1777             tcp_linger_tmo = get_linger_opt.l_linger;
1778          } else {
1779              debug(F101,
1780                    "TCP ck_linger new SO_LINGER",
1781                    "",
1782                    set_linger_opt.l_onoff
1783                    );
1784              tcp_linger = set_linger_opt.l_onoff;
1785              tcp_linger_tmo = set_linger_opt.l_linger;
1786              return 1;
1787          }
1788     } else {
1789         debug(F101,"TCP ck_linger SO_LINGER unchanged","",
1790               get_linger_opt.l_onoff);
1791         tcp_linger = get_linger_opt.l_onoff;
1792         tcp_linger_tmo = get_linger_opt.l_linger;
1793         return 1;
1794     }
1795 #else
1796     debug(F100,"TCP ck_linger SO_LINGER not defined","",0);
1797 #endif /* SO_LINGER */
1798 #else
1799     debug(F100,"TCP ck_linger SO_SOCKET not defined","",0);
1800 #endif /* SOL_SOCKET */
1801     return(0);
1802 }
1803
1804 int
1805 sendbuf(sock,size) int sock; int size; {
1806 /*
1807   The following, from William Bader, allows changing of socket buffer sizes,
1808   in case that might affect performance.
1809
1810   Modified by Jeff Altman to be generally useful.
1811 */
1812 #ifdef SOL_SOCKET
1813 #ifdef SO_SNDBUF
1814     int i, j;
1815     SOCKOPT_T x;
1816
1817 #ifdef IKSD
1818     if (!inserver)
1819 #endif /* IKSD */
1820       if (sock == -1 ||
1821         nettype != NET_TCPA && nettype != NET_TCPB && nettype != NET_SSH
1822                 || ttmdm >= 0) {
1823         tcp_sendbuf = size;
1824         return 1;
1825     }
1826     x = sizeof(i);
1827     if (getsockopt(sock, SOL_SOCKET, SO_SNDBUF, (char *)&i, &x)) {
1828         debug(F111,"TCP sendbuf can't get SO_SNDBUF",ck_errstr(),errno);
1829     } else if (x != sizeof(i)) {
1830 #ifdef OS2
1831         short i16,j16;
1832         if (x == sizeof(i16)) {
1833             debug(F111,"TCP sendbuf warning: SO_SNDBUF","len is 16-bit",x);
1834             if (getsockopt(sock,
1835                            SOL_SOCKET, SO_SNDBUF,
1836                            (char *)&i16, &x)
1837                 ) {
1838                 debug(F111,"TCP sendbuf can't get SO_SNDBUF",
1839                       ck_errstr(),errno);
1840             } else if (size <= 0) {
1841                 tcp_sendbuf = i16;
1842                 debug(F101,"TCP sendbuf SO_SNDBUF retrieved","",i16);
1843                 return 1;
1844             } else if (i16 != size) {
1845                 j16 = size;
1846                 if (setsockopt(sock,
1847                                SOL_SOCKET,
1848                                SO_SNDBUF,
1849                                (char *)&j16,
1850                                sizeof(j16))
1851                     ) {
1852                     debug(F111,"TCP sendbuf can't set SO_SNDBUF",
1853                           ck_errstr(),errno);
1854                 } else {
1855                     debug(F101,"TCP sendbuf old SO_SNDBUF","",i16);
1856                     debug(F101,"TCP sendbuf new SO_SNDBUF","",j16);
1857                     tcp_sendbuf = size;
1858                     return 1;
1859                 }
1860             } else {
1861                 debug(F101,"TCP sendbuf SO_SNDBUF unchanged","",i16);
1862                 tcp_sendbuf = size;
1863                 return 1;
1864             }
1865             return(0);
1866         }
1867 #endif /* OS2 */
1868         debug(F111,"TCP sendbuf error: SO_SNDBUF","len",x);
1869         debug(F111,"TCP sendbuf SO_SNDBUF","expected len",sizeof(i));
1870         debug(F111,"TCP sendbuf SO_SNDBUF","i",i);
1871     } else if (size <= 0) {
1872         tcp_sendbuf = i;
1873         debug(F101,"TCP sendbuf SO_SNDBUF retrieved","",i);
1874         return 1;
1875     } else if (i != size) {
1876         j = size;
1877         if (setsockopt(sock, SOL_SOCKET, SO_SNDBUF, (char *)&j, sizeof(j))) {
1878             debug(F111,"TCP sendbuf can't set SO_SNDBUF",ck_errstr(),errno);
1879             tcp_sendbuf = i;
1880         } else {
1881             debug(F101,"TCP sendbuf old SO_SNDBUF","",i);
1882             debug(F101,"TCP sendbuf new SO_SNDBUF","",j);
1883             tcp_sendbuf = size;
1884             return 1;
1885         }
1886     } else {
1887         debug(F101,"TCP sendbuf SO_SNDBUF unchanged","",i);
1888         tcp_sendbuf = size;
1889         return 1;
1890     }
1891 #else
1892     debug(F100,"TCP sendbuf SO_SNDBUF not defined","",0);
1893 #endif /* SO_SNDBUF */
1894 #else
1895     debug(F100,"TCP sendbuf SO_SOCKET not defined","",0);
1896 #endif /* SOL_SOCKET */
1897     return(0);
1898 }
1899
1900 int
1901 recvbuf(sock,size) int sock; int size; {
1902 /*
1903   The following, from William Bader, allows changing of socket buffer sizes,
1904   in case that might affect performance.
1905
1906   Modified by Jeff Altman to be generally useful.
1907 */
1908 #ifdef SOL_SOCKET
1909 #ifdef SO_RCVBUF
1910     int i, j;
1911     SOCKOPT_T x;
1912
1913 #ifdef IKSD
1914     if (!inserver)
1915 #endif /* IKSD */
1916       if (sock == -1 ||
1917           nettype != NET_TCPA && nettype != NET_TCPB &&
1918           nettype != NET_SSH || ttmdm >= 0) {
1919         tcp_recvbuf = size;
1920         return(1);
1921     }
1922     x = sizeof(i);
1923     if (getsockopt(sock, SOL_SOCKET, SO_RCVBUF, (char *)&i, &x)) {
1924         debug(F111,"TCP recvbuf can't get SO_RCVBUF",ck_errstr(),errno);
1925     } else if (x != sizeof(i)) {
1926 #ifdef OS2
1927         short i16,j16;
1928         if ( x == sizeof(i16) ) {
1929             debug(F111,"TCP recvbuf warning: SO_RCVBUF","len is 16-bit",x);
1930             if (getsockopt(sock,
1931                            SOL_SOCKET, SO_RCVBUF,
1932                            (char *)&i16, &x)
1933                 ) {
1934                 debug(F111,"TCP recvbuf can't get SO_RCVBUF",
1935                       ck_errstr(),errno);
1936             } else if (size <= 0) {
1937                 tcp_recvbuf = i16;
1938                 debug(F101,"TCP recvbuf SO_RCVBUF retrieved","",i16);
1939                 return 1;
1940             } else if (i16 != size) {
1941                 j16 = size;
1942                 if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF, (char *)&j16,
1943                                sizeof(j16))) {
1944                     debug(F111,"TCP recvbuf can' set SO_RCVBUF",
1945                           ck_errstr(),errno);
1946                 } else {
1947                     debug(F101,"TCP recvbuf old SO_RCVBUF","",i16);
1948                     debug(F101,"TCP recvbuf new SO_RCVBUF","",j16);
1949                     tcp_recvbuf = size;
1950                     return 1;
1951                 }
1952             } else {
1953                 debug(F101,"TCP recvbuf SO_RCVBUF unchanged","",i16);
1954                 tcp_recvbuf = size;
1955                 return 1;
1956             }
1957             return(0);
1958         }
1959 #endif /* OS2 */
1960         debug(F111,"TCP recvbuf error: SO_RCVBUF","len",x);
1961         debug(F111,"TCP recvbuf SO_RCVBUF","expected len",sizeof(i));
1962         debug(F111,"TCP recvbuf SO_RCVBUF","i",i);
1963     } else if (size <= 0) {
1964         tcp_recvbuf = i;
1965         debug(F101,"TCP recvbuf SO_RCVBUF retrieved","",i);
1966         return 1;
1967     } else if (i != size) {
1968         j = size;
1969         if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF, (char *)&j, sizeof(j))) {
1970             debug(F111,"TCP recvbuf can't set SO_RCVBUF",ck_errstr(),errno);
1971             tcp_recvbuf = i;
1972         } else {
1973             debug(F101,"TCP recvbuf old SO_RCVBUF","",i);
1974             debug(F101,"TCP recvbuf new SO_RCVBUF","",j);
1975             tcp_recvbuf = size;
1976             return 1;
1977         }
1978     } else {
1979         debug(F101,"TCP recvbuf SO_RCVBUF unchanged","",i);
1980         tcp_recvbuf = size;
1981         return 1;
1982     }
1983 #else
1984     debug(F100,"TCP recvbuf SO_RCVBUF not defined","",0);
1985 #endif /* SO_RCVBUF */
1986 #else
1987     debug(F100,"TCP recvbuf SO_SOCKET not defined","",0);
1988 #endif /* SOL_SOCKET */
1989     return 0;
1990 }
1991
1992 int
1993 keepalive(sock,onoff) int sock; int onoff; {
1994 #ifdef SOL_SOCKET
1995 #ifdef SO_KEEPALIVE
1996     int get_keepalive_opt;
1997     int set_keepalive_opt;
1998     SOCKOPT_T x;
1999
2000     debug(F111,"TCP keepalive","sock",sock);
2001     debug(F111,"TCP keepalive","nettype",nettype);
2002     debug(F111,"TCP keepalive","ttmdm",ttmdm);
2003
2004 #ifdef IKSD
2005     if (!inserver)
2006 #endif /* IKSD */
2007       if (sock == -1 ||
2008         nettype != NET_TCPA && nettype != NET_TCPB && nettype != NET_SSH
2009                 || ttmdm >= 0) {
2010         tcp_keepalive = onoff;
2011         return 1;
2012     }
2013     x = sizeof(get_keepalive_opt);
2014     if (getsockopt(sock,
2015                    SOL_SOCKET, SO_KEEPALIVE, (char *)&get_keepalive_opt, &x)) {
2016         debug(F111,"TCP keepalive can't get SO_KEEPALIVE",ck_errstr(),errno);
2017     } else if (x != sizeof(get_keepalive_opt)) {
2018 #ifdef OS2
2019         short get_keepalive_opt16;
2020         short set_keepalive_opt16;
2021         if (x == sizeof(get_keepalive_opt16)) {
2022             debug(F111,"TCP keepalive warning: SO_KEEPALIVE",
2023                   "len is 16-bit",x);
2024             if (getsockopt(sock,
2025                            SOL_SOCKET, SO_KEEPALIVE,
2026                            (char *)&get_keepalive_opt16, &x)
2027                 ) {
2028                 debug(F111,
2029                       "TCP keepalive can't get SO_KEEPALIVE",
2030                       ck_errstr(),
2031                       errno
2032                       );
2033             } else if (get_keepalive_opt16 != onoff) {
2034                 set_keepalive_opt16 = onoff;
2035                 if (setsockopt(sock,
2036                                SOL_SOCKET,
2037                                SO_KEEPALIVE,
2038                                (char *)&set_keepalive_opt16,
2039                                sizeof(set_keepalive_opt16))
2040                     ) {
2041                     debug(F111,
2042                           "TCP keepalive can't clear SO_KEEPALIVE",
2043                           ck_errstr(),
2044                           errno
2045                           );
2046                     tcp_keepalive = get_keepalive_opt16;
2047                 } else {
2048                     debug(F101,
2049                           "TCP keepalive new SO_KEEPALIVE","",
2050                           set_keepalive_opt16);
2051                     tcp_keepalive = set_keepalive_opt16;
2052                     return 1;
2053                 }
2054             } else {
2055                 debug(F101,"TCP keepalive SO_KEEPALIVE unchanged","",
2056                       get_keepalive_opt16);
2057                 tcp_keepalive = onoff;
2058                 return 1;
2059             }
2060             return(0);
2061         }
2062 #endif /* OS2 */
2063         debug(F111,"TCP keepalive error: SO_KEEPALIVE","len",x);
2064         debug(F111,
2065               "TCP keepalive SO_KEEPALIVE",
2066               "expected len",
2067               sizeof(get_keepalive_opt)
2068               );
2069         debug(F111,
2070               "TCP keepalive SO_KEEPALIVE",
2071               "keepalive_opt",
2072               get_keepalive_opt
2073               );
2074     } else if (get_keepalive_opt != onoff) {
2075             set_keepalive_opt = onoff;
2076             if (setsockopt(sock,
2077                             SOL_SOCKET,
2078                             SO_KEEPALIVE,
2079                             (char *)&set_keepalive_opt,
2080                             sizeof(set_keepalive_opt))
2081                 ) {
2082                 debug(F111,
2083                       "TCP keepalive can't clear SO_KEEPALIVE",
2084                       ck_errstr(),
2085                       errno
2086                       );
2087                 tcp_keepalive = get_keepalive_opt;
2088             } else {
2089                 debug(F101,
2090                       "TCP keepalive new SO_KEEPALIVE",
2091                       "",
2092                       set_keepalive_opt
2093                       );
2094                 tcp_keepalive = onoff;
2095                 return 1;
2096             }
2097         } else {
2098             debug(F101,"TCP keepalive SO_KEEPALIVE unchanged",
2099                   "",
2100                   get_keepalive_opt
2101                   );
2102             tcp_keepalive = onoff;
2103             return 1;
2104     }
2105 #else
2106     debug(F100,"TCP keepalive SO_KEEPALIVE not defined","",0);
2107 #endif /* SO_KEEPALIVE */
2108 #else
2109     debug(F100,"TCP keepalive SO_SOCKET not defined","",0);
2110 #endif /* SOL_SOCKET */
2111     return(0);
2112 }
2113
2114 int
2115 dontroute(sock,onoff) int sock; int onoff; {
2116 #ifdef SOL_SOCKET
2117 #ifdef SO_DONTROUTE
2118     int get_dontroute_opt;
2119     int set_dontroute_opt;
2120     SOCKOPT_T x;
2121
2122 #ifdef IKSD
2123     if (!inserver)
2124 #endif /* IKSD */
2125       if (sock == -1 ||
2126         nettype != NET_TCPA && nettype != NET_TCPB && nettype != NET_SSH
2127                 || ttmdm >= 0) {
2128         tcp_dontroute = onoff;
2129         return 1;
2130     }
2131     x = sizeof(get_dontroute_opt);
2132     if (getsockopt(sock,
2133                    SOL_SOCKET, SO_DONTROUTE, (char *)&get_dontroute_opt, &x)) {
2134         debug(F111,"TCP dontroute can't get SO_DONTROUTE",ck_errstr(),errno);
2135     } else if (x != sizeof(get_dontroute_opt)) {
2136 #ifdef OS2
2137         short get_dontroute_opt16;
2138         short set_dontroute_opt16;
2139         if (x == sizeof(get_dontroute_opt16)) {
2140             debug(F111,"TCP dontroute warning: SO_DONTROUTE",
2141                   "len is 16-bit",x);
2142             if (getsockopt(sock,
2143                            SOL_SOCKET, SO_DONTROUTE,
2144                            (char *)&get_dontroute_opt16, &x)
2145                 ) {
2146                 debug(F111,
2147                       "TCP dontroute can't get SO_DONTROUTE",
2148                       ck_errstr(),
2149                       errno
2150                       );
2151             } else if (get_dontroute_opt16 != onoff) {
2152                 set_dontroute_opt16 = onoff;
2153                 if (setsockopt(sock,
2154                                SOL_SOCKET,
2155                                SO_DONTROUTE,
2156                                (char *)&set_dontroute_opt16,
2157                                sizeof(set_dontroute_opt16))
2158                     ) {
2159                     debug(F111,
2160                           "TCP dontroute can't clear SO_DONTROUTE",
2161                           ck_errstr(),
2162                           errno
2163                           );
2164                     tcp_dontroute = get_dontroute_opt16;
2165                 } else {
2166                     debug(F101,
2167                           "TCP dontroute new SO_DONTROUTE","",
2168                           set_dontroute_opt16);
2169                     tcp_dontroute = set_dontroute_opt16;
2170                     return 1;
2171                 }
2172             } else {
2173                 debug(F101,"TCP dontroute SO_DONTROUTE unchanged","",
2174                       get_dontroute_opt16);
2175                 tcp_dontroute = onoff;
2176                 return 1;
2177             }
2178             return(0);
2179         }
2180 #endif /* OS2 */
2181         debug(F111,"TCP dontroute error: SO_DONTROUTE","len",x);
2182         debug(F111,
2183               "TCP dontroute SO_DONTROUTE",
2184               "expected len",
2185               sizeof(get_dontroute_opt)
2186               );
2187         debug(F111,
2188               "TCP dontroute SO_DONTROUTE",
2189               "dontroute_opt",
2190               get_dontroute_opt
2191               );
2192     } else if (get_dontroute_opt != onoff) {
2193             set_dontroute_opt = onoff;
2194             if (setsockopt(sock,
2195                             SOL_SOCKET,
2196                             SO_DONTROUTE,
2197                             (char *)&set_dontroute_opt,
2198                             sizeof(set_dontroute_opt))
2199                 ) {
2200                 debug(F111,
2201                       "TCP dontroute can't clear SO_DONTROUTE",
2202                       ck_errstr(),
2203                       errno
2204                       );
2205                 tcp_dontroute = get_dontroute_opt;
2206             } else {
2207                 debug(F101,
2208                       "TCP dontroute new SO_DONTROUTE",
2209                       "",
2210                       set_dontroute_opt
2211                       );
2212                 tcp_dontroute = onoff;
2213                 return 1;
2214             }
2215         } else {
2216             debug(F101,"TCP dontroute SO_DONTROUTE unchanged",
2217                   "",
2218                   get_dontroute_opt
2219                   );
2220             tcp_dontroute = onoff;
2221             return 1;
2222     }
2223 #else
2224     debug(F100,"TCP dontroute SO_DONTROUTE not defined","",0);
2225 #endif /* SO_DONTROUTE */
2226 #else
2227     debug(F100,"TCP dontroute SO_SOCKET not defined","",0);
2228 #endif /* SOL_SOCKET */
2229     return(0);
2230 }
2231
2232 int
2233 no_delay(sock,onoff)  int sock; int onoff; {
2234 #ifdef SOL_SOCKET
2235 #ifdef TCP_NODELAY
2236     int get_nodelay_opt;
2237     int set_nodelay_opt;
2238     SOCKOPT_T x;
2239
2240 #ifdef IKSD
2241     if (!inserver)
2242 #endif /* IKSD */
2243       if (sock == -1 ||
2244         nettype != NET_TCPA && nettype != NET_TCPB && nettype != NET_SSH
2245                 || ttmdm >= 0) {
2246         tcp_nodelay = onoff;
2247         return(1);
2248     }
2249     x = sizeof(get_nodelay_opt);
2250     if (getsockopt(sock,IPPROTO_TCP,TCP_NODELAY,
2251                    (char *)&get_nodelay_opt,&x)) {
2252         debug(F111,
2253               "TCP no_delay can't get TCP_NODELAY",
2254               ck_errstr(),
2255               errno);
2256     } else if (x != sizeof(get_nodelay_opt)) {
2257 #ifdef OS2
2258         short get_nodelay_opt16;
2259         short set_nodelay_opt16;
2260         if (x == sizeof(get_nodelay_opt16)) {
2261             debug(F111,"TCP no_delay warning: TCP_NODELAY","len is 16-bit",x);
2262             if (getsockopt(sock,
2263                            IPPROTO_TCP, TCP_NODELAY,
2264                            (char *)&get_nodelay_opt16, &x)
2265                 ) {
2266                 debug(F111,
2267                       "TCP no_delay can't get TCP_NODELAY",
2268                       ck_errstr(),
2269                       errno);
2270             } else if (get_nodelay_opt16 != onoff) {
2271                 set_nodelay_opt16 = onoff;
2272                 if (setsockopt(sock,
2273                                IPPROTO_TCP,
2274                                TCP_NODELAY,
2275                                (char *)&set_nodelay_opt16,
2276                                sizeof(set_nodelay_opt16))
2277                     ) {
2278                     debug(F111,
2279                           "TCP no_delay can't clear TCP_NODELAY",
2280                           ck_errstr(),
2281                           errno);
2282                     tcp_nodelay = get_nodelay_opt16;
2283                 } else {
2284                     debug(F101,
2285                           "TCP no_delay new TCP_NODELAY",
2286                           "",
2287                           set_nodelay_opt16);
2288                     tcp_nodelay = onoff;
2289                     return 1;
2290                 }
2291             } else {
2292                 debug(F101,"TCP no_delay TCP_NODELAY unchanged","",
2293                       get_nodelay_opt16);
2294                 tcp_nodelay = onoff;
2295                 return 1;
2296             }
2297             return(0);
2298         }
2299 #endif /* OS2 */
2300         debug(F111,"TCP no_delay error: TCP_NODELAY","len",x);
2301         debug(F111,"TCP no_delay TCP_NODELAY","expected len",
2302               sizeof(get_nodelay_opt));
2303         debug(F111,"TCP no_delay TCP_NODELAY","nodelay_opt",get_nodelay_opt);
2304     } else if (get_nodelay_opt != onoff) {
2305         set_nodelay_opt = onoff;
2306         if (setsockopt(sock,
2307                        IPPROTO_TCP,
2308                        TCP_NODELAY,
2309                        (char *)&set_nodelay_opt,
2310                        sizeof(set_nodelay_opt))) {
2311             debug(F111,
2312                   "TCP no_delay can't clear TCP_NODELAY",
2313                   ck_errstr(),
2314                   errno
2315                   );
2316             tcp_nodelay = get_nodelay_opt;
2317         } else {
2318             debug(F101,"TCP no_delay new TCP_NODELAY","",set_nodelay_opt);
2319             tcp_nodelay = onoff;
2320             return 1;
2321         }
2322     } else {
2323         debug(F101,"TCP no_delay TCP_NODELAY unchanged","",get_nodelay_opt);
2324         tcp_nodelay = onoff;
2325         return(1);
2326     }
2327 #else
2328     debug(F100,"TCP no_delay TCP_NODELAY not defined","",0);
2329 #endif /* TCP_NODELAY */
2330 #else
2331     debug(F100,"TCP no_delay SO_SOCKET not defined","",0);
2332 #endif /* SOL_SOCKET */
2333     return 0;
2334 }
2335 #endif /* datageneral */
2336 #endif /* NOTCPOPTS */
2337
2338 #ifdef SUNX25
2339 #ifndef X25_WR_FACILITY
2340 /* For Solaris 2.3 / SunLink 8.x - see comments in ckcnet.h */
2341 void
2342 bzero(s,n) char *s; int n; {
2343     memset(s,0,n);
2344 }
2345 #endif /* X25_WR_FACILITY */
2346 #endif /* SUNX25 */
2347
2348 #ifdef TCPSOCKET
2349 #ifndef OS2
2350 #ifndef NOLISTEN
2351
2352 #ifdef BSDSELECT
2353 #ifndef VMS
2354 #ifndef BELLV10
2355 #ifndef datageneral
2356 #ifdef hp9000s500                       /* HP-9000/500 HP-U 5.21 */
2357 #include <time.h>
2358 #else
2359
2360 /****** THIS SECTION ADDED BY STEVE RANCE - OS9 NETWORK SERVER
2361 *       ------------------------------------------------------
2362 *
2363 *       Due to OS9's Lack of a select() call, the following seems to be
2364 *       enough to fool the rest of the code into compiling. The only
2365 *       effect that I can see is using control L to refresh the status
2366 *       display gets qued up until some network packets arrive.
2367 *
2368 *       This solution is by no means elegant but works enough to be
2369 *       a (the) solution.
2370 *
2371 *       Also with the defines I had specified in my makefile I had to
2372 *       have an #endif right at the end of the file when compiling.
2373 *       I did not bother speding time to find out why.
2374 *
2375 *       COPTS   = -to=osk -d=OSK -d=TCPSOCKET -d=SELECT -d=VOID=void -d=SIG_V \
2376 *          -d=DYNAMIC -d=PARSENSE -d=KANJI -d=MYCURSES -d=ZFCDAT \
2377 *          -d=CK_APC -d=CK_REDIR -d=RENAME -d=CK_TTYFD -d=NOOLDMODEMS \
2378 *          -d=CK_ANSIC -d=CK_XYZ -tp=68040d -l=netdb.l -l=socklib.l \
2379 *          -l=termlib.l -l=math.l -l=sys_clib.l
2380 *
2381 *       stever@ozemail.com.au
2382 */
2383
2384 #ifdef  OSK
2385 #define BSDSELECT                       /* switch on BSD select code */
2386 #define FD_SETSIZE 32                   /* Max # of paths in OS9 */
2387 #define FD_ZERO(p)                      ((*p)=0)
2388 #define FD_SET(n,b)                     ((*b)|=(1<<(n)))
2389 #define FD_ISSET(n,b)           1       /* always say data is ready */
2390 #define select(a,b,c,d,e)       1       /* always say 1 path has data */
2391 typedef int     fd_set;                 /* keep BSD Code Happy */
2392 struct timeval {int tv_sec,tv_usec;};   /* keep BSD Code Happy */
2393
2394 /****** END OF OS9 MODS FROM STEVE RANCE **************************/
2395 #endif /* OSK */
2396
2397 #include <sys/time.h>
2398 #endif /* hp9000s500 */
2399 #endif /* datageneral */
2400 #endif /* BELLV10 */
2401 #endif /* VMS */
2402 #ifdef SELECT_H
2403 #include <sys/select.h>
2404 #endif /* SELECT_H */
2405 #endif /* BSDSELECT */
2406
2407 #ifdef SELECT
2408 #ifdef CK_SCOV5
2409 #include <sys/select.h>
2410 #endif /* CK_SCOV5 */
2411 #endif /* SELECT */
2412
2413 #ifdef NOTUSED
2414 /* T C P S O C K E T _ O P E N -- Open a preexisting socket number */
2415
2416 int
2417 tcpsocket_open(name,lcl,nett,timo) char * name; int * lcl; int nett; int timo {
2418     int on = 1;
2419     static struct servent *service, servrec;
2420     static struct hostent *host;
2421     static struct sockaddr_in saddr;
2422     static
2423 #ifdef UCX50
2424       unsigned
2425 #endif /* UCX50 */
2426       int saddrlen;
2427 #ifdef BSDSELECT
2428     fd_set rfds;
2429     struct timeval tv;
2430 #else
2431 #ifdef BELLSELECT
2432     fd_set rfds;
2433 #else
2434     fd_set rfds;
2435     fd_set rfds;
2436     struct timeval {
2437         long tv_sec;
2438         long tv_usec;
2439     } tv;
2440 #endif /* BELLSELECT */
2441 #endif /* BSDSELECT */
2442
2443     debug(F101,"tcpsocket_open nett","",nett);
2444     *ipaddr = '\0';
2445
2446     if (nett != NET_TCPB)
2447       return(-1);                       /* BSD socket support */
2448
2449     netclos();                          /* Close any previous connection. */
2450     ckstrncpy(namecopy, name, NAMECPYL); /* Copy the hostname. */
2451 #ifdef COMMENT
2452     /* Jeff's version from 30 Dec 2005 doesn't inhibit Telnet */
2453     if (ttnproto != NP_TCPRAW &&
2454         ttnproto != NP_SSL_RAW &&
2455         ttnproto != NP_TLS_RAW)
2456       ttnproto = NP_NONE;               /* No protocol selected yet. */
2457 #else
2458     /* fdc's version from 4 Dec 2005 works ok */
2459     if (ttnproto != NP_TCPRAW)
2460       ttnproto = NP_NONE;               /* No protocol selected yet. */
2461 #endif  /* COMMENT */
2462     debug(F110,"tcpsocket_open namecopy",namecopy,0);
2463
2464     /* Assign the socket number to ttyfd and then fill in tcp structures */
2465     ttyfd = atoi(&name[1]);
2466     debug(F111,"tcpsocket_open","ttyfd",ttyfd);
2467
2468 #ifndef NOTCPOPTS
2469 #ifdef SOL_SOCKET
2470     setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
2471
2472 #ifndef datageneral
2473 #ifdef TCP_NODELAY
2474     no_delay(ttyfd,tcp_nodelay);
2475 #endif /* TCP_NODELAY */
2476 #ifdef SO_KEEPALIVE
2477     keepalive(ttyfd,tcp_keepalive);
2478 #endif /* SO_KEEPALIVE */
2479 #ifdef SO_LINGER
2480     ck_linger(ttyfd,tcp_linger, tcp_linger_tmo);
2481 #endif /* SO_LINGER */
2482 #ifdef SO_SNDBUF
2483     sendbuf(ttyfd,tcp_sendbuf);
2484 #endif /* SO_SNDBUF */
2485 #ifdef SO_RCVBUF
2486     recvbuf(ttyfd,tcp_recvbuf);
2487 #endif /* SO_RCVBUF */
2488 #endif /* datageneral */
2489 #endif /* SOL_SOCKET */
2490 #endif /* NOTCPOPTS */
2491
2492 #ifdef NT_TCP_OVERLAPPED
2493     OverlappedWriteInit();
2494     OverlappedReadInit();
2495 #endif /* NT_TCP_OVERLAPPED */
2496
2497
2498     /* Get the name of the host we are connected to */
2499
2500     saddrlen = sizeof(saddr);
2501     getpeername(ttyfd,(struct sockaddr *)&saddr,&saddrlen);
2502
2503     ckstrncpy(ipaddr,(char *)inet_ntoa(saddr.sin_addr),20);
2504
2505     if (tcp_rdns == SET_ON
2506 #ifdef CK_KERBEROS
2507         || tcp_rdns == SET_AUTO &&
2508          (ck_krb5_is_installed() || ck_krb4_is_installed())
2509 #endif /* CK_KERBEROS */
2510 #ifndef NOHTTP
2511           && (tcp_http_proxy == NULL)
2512 #endif /* NOHTTP */
2513 #ifdef CK_SSL
2514           && !(ssl_only_flag || tls_only_flag)
2515 #endif /* CK_SSL */
2516          ) {                            /* Reverse DNS */
2517         if (!quiet) {
2518             printf(" Reverse DNS Lookup... ");
2519             fflush(stdout);
2520         }
2521         host = gethostbyaddr((char *)&saddr.sin_addr,4,PF_INET);
2522         debug(F110,"tcpsocket_open gethostbyaddr",host ? "OK" : "FAILED",0);
2523         if (host) {
2524             host = ck_copyhostent(host);
2525             debug(F100,"tcpsocket_open gethostbyaddr != NULL","",0);
2526             if (!quiet) {
2527                 printf("(OK)\n");
2528                 fflush(stdout);
2529             }
2530             ckstrncpy(name, host->h_name, 80);
2531             ckstrncat(name, ":", 80);
2532             ckstrncat(name,ckuitoa(ntohs(saddr.sin_port)), 80);
2533             if (!quiet
2534 #ifndef NOICP
2535                 && !doconx
2536 #endif /* NOICP */
2537                 )
2538               printf("%s connected on port %d\n",
2539                    host->h_name,
2540                    ntohs(saddr.sin_port)
2541                    );
2542         } else if (!quiet)
2543           printf("Failed\n");
2544     } else if (!quiet)
2545       printf("(OK)\n");
2546
2547     if (tcp_rdns != SET_ON || !host) {
2548         ckstrncpy(name,ipaddr,80);
2549         ckstrncat(name,":",80);
2550         ckstrncat(name,ckuitoa(ntohs(saddr.sin_port)),80);
2551         if (!quiet
2552 #ifdef NOICP
2553             && !doconx
2554 #endif /* NOICP */
2555             )
2556           printf("%s connected on port %d\n",ipaddr,ntohs(saddr.sin_port));
2557     }
2558     if (!quiet) fflush(stdout);
2559     ttnet = nett;                       /* TCP/IP (sockets) network */
2560
2561 #ifdef RLOGCODE
2562     if (ntohs(saddr.sin_port) == 513)
2563         ttnproto = NP_LOGIN;
2564     else
2565 #endif /* RLOGCODE */
2566     /* Assume the service is TELNET. */
2567 #ifdef COMMENT
2568       /* Jeff's code from 2005/12/30 */
2569       if (ttnproto != NP_TCP_RAW &&
2570           ttnproto != NP_SSL_RAW &&
2571           ttnproto != NP_TLS_RAW)
2572 #else
2573       /* fdc's code from 2005/12/04 */
2574       if (ttnproto != NP_TCPRAW)
2575 #endif  /* COMMENT */
2576         ttnproto = NP_TELNET;           /* Yes, set global flag. */
2577 #ifdef CK_SECURITY
2578     /* Before Initialization Telnet/Rlogin Negotiations Init Kerberos */
2579     ck_auth_init((tcp_rdns && host && host->h_name && host->h_name[0]) ?
2580                 host->h_name : ipaddr,
2581                 ipaddr,
2582                 uidbuf,
2583                 ttyfd
2584                 );
2585 #endif /* CK_SECURITY */
2586     if (tn_ini() < 0)                   /* Start/Reset TELNET negotiations */
2587       if (ttchk() < 0)                  /* Did it fail due to connect loss? */
2588         return(-1);
2589
2590     if (*lcl < 0) *lcl = 1;             /* Local mode. */
2591
2592     return(0);                          /* Done. */
2593 }
2594 #endif /* NOTUSED */
2595
2596 /*  T C P S R V _ O P E N  --  Open a TCP/IP Server connection  */
2597 /*
2598   Calling conventions same as ttopen(), except third argument is network
2599   type rather than modem type.
2600 */
2601 int
2602 tcpsrv_open(name,lcl,nett,timo) char * name; int * lcl; int nett; int timo; {
2603     char *p;
2604     int i, x;
2605     SOCKOPT_T on = 1;
2606     int ready_to_accept = 0;
2607     static struct servent *service, *service2, servrec;
2608     static struct hostent *host;
2609     static struct sockaddr_in saddr;
2610     struct sockaddr_in l_addr;
2611     GSOCKNAME_T l_slen;
2612 #ifdef UCX50
2613     static u_int saddrlen;
2614 #else
2615     static SOCKOPT_T saddrlen;
2616 #endif /* UCX50 */
2617
2618 #ifdef BSDSELECT
2619     fd_set rfds;
2620     struct timeval tv;
2621 #else
2622 #ifdef BELLSELCT
2623     fd_set rfds;
2624 #else
2625     fd_set rfds;
2626     struct timeval {
2627         long tv_sec;
2628         long tv_usec;
2629     } tv;
2630 #endif /* BELLSELECT */
2631 #endif /* BSDSELECT */
2632 #ifdef CK_SSL
2633     int ssl_failed = 0;
2634 #endif /* CK_SSL */
2635
2636     debug(F101,"tcpsrv_open nett","",nett);
2637     *ipaddr = '\0';
2638
2639     if (nett != NET_TCPB)
2640       return(-1);                       /* BSD socket support */
2641
2642     netclos();                          /* Close any previous connection. */
2643     ckstrncpy(namecopy, name, NAMECPYL); /* Copy the hostname. */
2644     /* Don't do this. */
2645 #ifdef COMMENT
2646     /* fdc */
2647     if (ttnproto != NP_TCPRAW)
2648       ttnproto = NP_NONE;               /* No protocol selected yet. */
2649 #endif  /* COMMENT */
2650 #ifdef COMMENT
2651     /* Jeff */
2652     if (ttnproto != NP_TCP_RAW &&
2653         ttnproto != NP_SSL_RAW &&
2654         ttnproto != NP_TLS_RAW)
2655       ttnproto = NP_NONE;               /* No protocol selected yet. */
2656 #endif /* COMMENT */
2657     debug(F110,"tcpsrv_open namecopy",namecopy,0);
2658
2659     p = namecopy;                       /* Was a service requested? */
2660     while (*p != '\0' && *p != ':')
2661       p++; /* Look for colon */
2662     if (*p == ':') {                    /* Have a colon */
2663         *p++ = '\0';                    /* Get service name or number */
2664     } else {                            /* Otherwise use kermit */
2665         p = "kermit";
2666     }
2667     debug(F110,"tcpsrv_open service requested",p,0);
2668     if (isdigit(*p)) {                  /* Use socket number without lookup */
2669         service = &servrec;
2670         service->s_port = htons((unsigned short)atoi(p));
2671     } else {                            /* Otherwise lookup the service name */
2672         service = getservbyname(p, "tcp");
2673     }
2674     if (!service && !strcmp("kermit",p)) { /* Use Kermit service port */
2675         service = &servrec;
2676         service->s_port = htons(1649);
2677     }
2678 #ifdef RLOGCODE
2679     if (service && !strcmp("login",p) && service->s_port != htons(513)) {
2680         fprintf(stderr,
2681                 "  Warning: login service on port %d instead of port 513\n",
2682                  ntohs(service->s_port));
2683         fprintf(stderr, "  Edit SERVICES file if RLOGIN fails to connect.\n");
2684         debug(F101,"tcpsrv_open login on port","",ntohs(service->s_port));
2685     }
2686 #endif /* RLOGCODE */
2687     if (!service) {
2688         fprintf(stderr, "Cannot find port for service: %s\n", p);
2689         debug(F111,"tcpsrv_open can't get service",p,errno);
2690         errno = 0;                      /* rather than mislead */
2691         return(-1);
2692     }
2693
2694     /* If we currently have a listen active but port has changed then close */
2695
2696     debug(F101,"tcpsrv_open checking previous connection","",tcpsrfd);
2697     debug(F101,"tcpsrv_open previous tcpsrv_port","",tcpsrv_port);
2698     if (tcpsrfd != -1 &&
2699         tcpsrv_port != ntohs((unsigned short)service->s_port)) {
2700         debug(F100,"tcpsrv_open closing previous connection","",0);
2701 #ifdef TCPIPLIB
2702         socket_close(tcpsrfd);
2703 #else
2704         close(tcpsrfd);
2705 #endif /* TCPIPLIB */
2706         tcpsrfd = -1;
2707     }
2708     debug(F100,"tcpsrv_open tcpsrfd","",tcpsrfd);
2709     if (tcpsrfd == -1) {
2710
2711         /* Set up socket structure and get host address */
2712
2713         bzero((char *)&saddr, sizeof(saddr));
2714         debug(F100,"tcpsrv_open bzero ok","",0);
2715         saddr.sin_family = AF_INET;
2716         if (tcp_address) {
2717 #ifdef INADDRX
2718             inaddrx = inet_addr(tcp_address);
2719             saddr.sin_addr.s_addr = *(unsigned long *)&inaddrx;
2720 #else
2721             saddr.sin_addr.s_addr = inet_addr(tcp_address);
2722 #endif /* INADDRX */
2723         } else
2724           saddr.sin_addr.s_addr = INADDR_ANY;
2725
2726         /* Get a file descriptor for the connection. */
2727
2728         saddr.sin_port = service->s_port;
2729         ipaddr[0] = '\0';
2730
2731         debug(F100,"tcpsrv_open calling socket","",0);
2732         if ((tcpsrfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
2733             perror("TCP socket error");
2734             debug(F101,"tcpsrv_open socket error","",errno);
2735             return (-1);
2736         }
2737         errno = 0;
2738
2739         /* Specify the Port may be reused */
2740
2741         debug(F100,"tcpsrv_open calling setsockopt","",0);
2742         x = setsockopt(tcpsrfd,
2743                        SOL_SOCKET,SO_REUSEADDR,(char *)&on,sizeof on);
2744         debug(F101,"tcpsrv_open setsockopt","",x);
2745
2746        /* Now bind to the socket */
2747         printf("\nBinding socket to port %d ...\n",
2748                ntohs((unsigned short)service->s_port));
2749         if (bind(tcpsrfd, (struct sockaddr *)&saddr, sizeof(saddr)) < 0) {
2750             i = errno;                  /* Save error code */
2751 #ifdef TCPIPLIB
2752             socket_close(tcpsrfd);
2753 #else /* TCPIPLIB */
2754             close(tcpsrfd);
2755 #endif /* TCPIPLIB */
2756             tcpsrfd = -1;
2757             tcpsrv_port = 0;
2758             ttyfd = -1;
2759             wasclosed = 1;
2760             errno = i;                  /* and report this error */
2761             debug(F101,"tcpsrv_open bind errno","",errno);
2762             printf("?Unable to bind to socket (errno = %d)\n",errno);
2763             return(-1);
2764         }
2765         debug(F100,"tcpsrv_open bind OK","",0);
2766         printf("Listening ...\n");
2767         if (listen(tcpsrfd, 15) < 0) {
2768             i = errno;                  /* Save error code */
2769 #ifdef TCPIPLIB
2770             socket_close(tcpsrfd);
2771 #else /* TCPIPLIB */
2772             close(tcpsrfd);
2773 #endif /* TCPIPLIB */
2774             tcpsrfd = -1;
2775             tcpsrv_port = 0;
2776             ttyfd = -1;
2777             wasclosed = 1;
2778             errno = i;                  /* And report this error */
2779             debug(F101,"tcpsrv_open listen errno","",errno);
2780             return(-1);
2781         }
2782         debug(F100,"tcpsrv_open listen OK","",0);
2783         tcpsrv_port = ntohs((unsigned short)service->s_port);
2784     }
2785
2786 #ifdef CK_SSL
2787     if (ck_ssleay_is_installed()) {
2788         if (!ssl_tn_init(SSL_SERVER)) {
2789             ssl_failed = 1;
2790             if (bio_err!=NULL) {
2791                 BIO_printf(bio_err,"do_ssleay_init() failed\n");
2792                 ERR_print_errors(bio_err);
2793             } else {
2794                 fflush(stderr);
2795                 fprintf(stderr,"do_ssleay_init() failed\n");
2796                 ERR_print_errors_fp(stderr);
2797             }
2798             if (tls_only_flag || ssl_only_flag) {
2799 #ifdef TCPIPLIB
2800                 socket_close(ttyfd);
2801                 socket_close(tcpsrfd);
2802 #else /* TCPIPLIB */
2803                 close(ttyfd);
2804                 close(tcpsrfd);
2805 #endif /* TCPIPLIB */
2806                 ttyfd = -1;
2807                 wasclosed = 1;
2808                 tcpsrfd = -1;
2809                 tcpsrv_port = 0;
2810                 return(-1);
2811             }
2812             /* we will continue to accept the connection   */
2813             /* without SSL or TLS support unless required. */
2814             if ( TELOPT_DEF_S_ME_MODE(TELOPT_START_TLS) != TN_NG_MU )
2815                 TELOPT_DEF_S_ME_MODE(TELOPT_START_TLS) = TN_NG_RF;
2816             if ( TELOPT_DEF_S_U_MODE(TELOPT_START_TLS) != TN_NG_MU )
2817                 TELOPT_DEF_S_U_MODE(TELOPT_START_TLS) = TN_NG_RF;
2818             if ( TELOPT_DEF_C_ME_MODE(TELOPT_START_TLS) != TN_NG_MU )
2819                 TELOPT_DEF_C_ME_MODE(TELOPT_START_TLS) = TN_NG_RF;
2820             if ( TELOPT_DEF_C_U_MODE(TELOPT_START_TLS) != TN_NG_MU )
2821                 TELOPT_DEF_C_U_MODE(TELOPT_START_TLS) = TN_NG_RF;
2822         }
2823     }
2824 #endif /* CK_SSL */
2825
2826     printf("\nWaiting to Accept a TCP/IP connection on port %d ...\n",
2827            ntohs((unsigned short)service->s_port));
2828     saddrlen = sizeof(saddr);
2829
2830 #ifdef BSDSELECT
2831     tv.tv_sec  = tv.tv_usec = 0L;
2832     if (timo < 0)
2833       tv.tv_usec = (long) -timo * 10000L;
2834     else
2835       tv.tv_sec = timo;
2836     debug(F101,"tcpsrv_open BSDSELECT","",timo);
2837 #else
2838     debug(F101,"tcpsrv_open not BSDSELECT","",timo);
2839 #endif /* BSDSELECT */
2840
2841     if (timo) {
2842         while (!ready_to_accept) {
2843 #ifdef BSDSELECT
2844             FD_ZERO(&rfds);
2845             FD_SET(tcpsrfd, &rfds);
2846             ready_to_accept =
2847               ((select(FD_SETSIZE,
2848 #ifdef HPUX
2849 #ifdef HPUX1010
2850                        (fd_set *)
2851 #else
2852
2853                        (int *)
2854 #endif /* HPUX1010 */
2855 #else
2856 #ifdef __DECC
2857 #ifdef INTSELECT
2858                        (int *)
2859 #else /* def INTSELECT */
2860                        (fd_set *)
2861 #endif /* def INTSELECT [else] */
2862 #endif /* __DECC */
2863 #endif /* HPUX */
2864                        &rfds, NULL, NULL, &tv) > 0) &&
2865                FD_ISSET(tcpsrfd, &rfds));
2866 #else /* BSDSELECT */
2867 #ifdef IBMSELECT
2868 #define ck_sleepint 250
2869             ready_to_accept =
2870               (select(&tcpsrfd, 1, 0, 0,
2871                       timo < 0 ? -timo :
2872                       (timo > 0 ? timo * 1000L : ck_sleepint)) == 1
2873                );
2874 #else
2875 #ifdef BELLSELECT
2876             FD_ZERO(rfds);
2877             FD_SET(tcpsrfd, rfds);
2878             ready_to_accept =
2879               ((select(128, rfds, NULL, NULL, timo < 0 ? -timo :
2880                       (timo > 0 ? timo * 1000L)) > 0) &&
2881                FD_ISSET(tcpsrfd, rfds));
2882 #else
2883 /* Try this - what's the worst that can happen... */
2884
2885             FD_ZERO(&rfds);
2886             FD_SET(tcpsrfd, &rfds);
2887             ready_to_accept =
2888               ((select(FD_SETSIZE,
2889                        (fd_set *) &rfds, NULL, NULL, &tv) > 0) &&
2890                FD_ISSET(tcpsrfd, &rfds));
2891
2892 #endif /* BELLSELECT */
2893 #endif /* IBMSELECT */
2894 #endif /* BSDSELECT */
2895         }
2896     }
2897     if (ready_to_accept || timo == 0) {
2898         if ((ttyfd = accept(tcpsrfd,
2899                             (struct sockaddr *)&saddr,&saddrlen)) < 0) {
2900             i = errno;                  /* save error code */
2901 #ifdef TCPIPLIB
2902             socket_close(tcpsrfd);
2903 #else /* TCPIPLIB */
2904             close(tcpsrfd);
2905 #endif /* TCPIPLIB */
2906             ttyfd = -1;
2907             wasclosed = 1;
2908             tcpsrfd = -1;
2909             tcpsrv_port = 0;
2910             errno = i;                  /* and report this error */
2911             debug(F101,"tcpsrv_open accept errno","",errno);
2912             return(-1);
2913         }
2914         setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
2915
2916 #ifndef NOTCPOPTS
2917 #ifndef datageneral
2918 #ifdef SOL_SOCKET
2919 #ifdef TCP_NODELAY
2920         no_delay(ttyfd,tcp_nodelay);
2921         debug(F101,"tcpsrv_open no_delay","",tcp_nodelay);
2922 #endif /* TCP_NODELAY */
2923 #ifdef SO_KEEPALIVE
2924         keepalive(ttyfd,tcp_keepalive);
2925         debug(F101,"tcpsrv_open keepalive","",tcp_keepalive);
2926 #endif /* SO_KEEPALIVE */
2927 #ifdef SO_LINGER
2928         ck_linger(ttyfd,tcp_linger, tcp_linger_tmo);
2929         debug(F101,"tcpsrv_open linger","",tcp_linger_tmo);
2930 #endif /* SO_LINGER */
2931 #ifdef SO_SNDBUF
2932         sendbuf(ttyfd,tcp_sendbuf);
2933 #endif /* SO_SNDBUF */
2934 #ifdef SO_RCVBUF
2935         recvbuf(ttyfd,tcp_recvbuf);
2936 #endif /* SO_RCVBUF */
2937 #endif /* SOL_SOCKET */
2938 #endif /* datageneral */
2939 #endif /* NOTCPOPTS */
2940
2941         ttnet = nett;                   /* TCP/IP (sockets) network */
2942         tcp_incoming = 1;               /* This is an incoming connection */
2943         sstelnet = 1;                   /* Do server-side Telnet protocol */
2944
2945         /* See if the service is TELNET. */
2946         x = (unsigned short)service->s_port;
2947         service2 = getservbyname("telnet", "tcp");
2948         if (service2 && x == service2->s_port) {
2949 #ifdef COMMENT
2950             /* Jeff 2005/12/30 */
2951             if (ttnproto != NP_TCPRAW && /* Yes... */
2952                  ttnproto != NP_SSL_RAW &&
2953                  ttnproto != NP_TLS_RAW) /* and if raw port not requested */
2954 #else
2955             /* fdc 2005/12/04 */
2956             if (ttnproto != NP_TCPRAW)  /* Yes and if raw port not requested */
2957 #endif  /*  */
2958               ttnproto = NP_TELNET;     /* set protocol to TELNET. */
2959         }
2960         ckstrncpy(ipaddr,(char *)inet_ntoa(saddr.sin_addr),20);
2961         if (tcp_rdns) {
2962             if (!quiet) {
2963                 printf(" Reverse DNS Lookup... ");
2964                 fflush(stdout);
2965             }
2966             if (host = gethostbyaddr((char *)&saddr.sin_addr,4,PF_INET)) {
2967                 host = ck_copyhostent(host);
2968                 debug(F100,"tcpsrv_open gethostbyaddr != NULL","",0);
2969                 if (!quiet) {
2970                     printf("(OK)\n");
2971                     fflush(stdout);
2972                 }
2973                 name[0] = '*';
2974                 ckstrncpy(&name[1],host->h_name,78);
2975                 ckstrncat(name,":",80-strlen(name));
2976                 ckstrncat(name,p,80-strlen(name));
2977                 if (!quiet
2978 #ifndef NOICP
2979                     && !doconx
2980 #endif /* NOICP */
2981                     )
2982                   printf("%s connected on port %s\n",host->h_name,p);
2983             } else {
2984                 if (!quiet) printf("Failed.\n");
2985             }
2986         } else if (!quiet) printf("(OK)\n");
2987
2988         if (!tcp_rdns || !host) {
2989             ckstrncpy(name,ipaddr,80);
2990             ckstrncat(name,":",80);
2991             ckstrncat(name,ckuitoa(ntohs(saddr.sin_port)),80);
2992             if (!quiet
2993 #ifndef NOICP
2994                 && !doconx
2995 #endif /* NOICP */
2996                 )
2997               printf("%s connected on port %d\n",ipaddr,ntohs(saddr.sin_port));
2998         }
2999         if (!quiet) fflush(stdout);
3000
3001 #ifdef CK_SECURITY
3002         /* Before Initialization Telnet/Rlogin Negotiations Init Kerberos */
3003         ck_auth_init((tcp_rdns && host && host->h_name && host->h_name[0]) ?
3004                      (char *)host->h_name : ipaddr,
3005                      ipaddr,
3006                      uidbuf,
3007                      ttyfd
3008                      );
3009 #endif /* CK_SECURITY */
3010
3011 #ifdef CK_SSL
3012         if (ck_ssleay_is_installed() && !ssl_failed) {
3013             if (ck_ssl_incoming(ttyfd) < 0) {
3014 #ifdef TCPIPLIB
3015                     socket_close(ttyfd);
3016                     socket_close(tcpsrfd);
3017 #else /* TCPIPLIB */
3018                     close(ttyfd);
3019                     close(tcpsrfd);
3020 #endif /* TCPIPLIB */
3021                     ttyfd = -1;
3022                     wasclosed = 1;
3023                     tcpsrfd = -1;
3024                     tcpsrv_port = 0;
3025                     return(-1);
3026             }
3027         }
3028 #endif /* CK_SSL */
3029
3030 #ifndef datageneral
3031         /* Find out our own IP address. */
3032         l_slen = sizeof(l_addr);
3033         bzero((char *)&l_addr, l_slen);
3034 #ifndef EXCELAN
3035         if (!getsockname(ttyfd, (struct sockaddr *)&l_addr, &l_slen)) {
3036             char * s = (char *)inet_ntoa(l_addr.sin_addr);
3037             ckstrncpy(myipaddr, s,20);
3038             debug(F110,"getsockname",myipaddr,0);
3039         }
3040 #endif /* EXCELAN */
3041 #endif /* datageneral */
3042
3043         if (tn_ini() < 0)               /* Start TELNET negotiations. */
3044           if (ttchk() < 0) {            /* Disconnected? */
3045               i = errno;                /* save error code */
3046 #ifdef TCPIPLIB
3047               socket_close(tcpsrfd);
3048 #else /* TCPIPLIB */
3049               close(tcpsrfd);
3050 #endif /* TCPIPLIB */
3051               ttyfd = -1;
3052               wasclosed = 1;
3053               tcpsrfd = -1;
3054               tcpsrv_port = 0;
3055               errno = i;                /* and report this error */
3056               debug(F101,"tcpsrv_open accept errno","",errno);
3057               return(-1);
3058           }
3059         debug(F101,"tcpsrv_open service","",x);
3060         if (*lcl < 0)                   /* Set local mode. */
3061           *lcl = 1;
3062
3063 #ifdef CK_KERBEROS
3064 #ifdef KRB5_U2U
3065         if ( ttnproto == NP_K5U2U ) {
3066             if (k5_user_to_user_server_auth() != 0) {
3067                 i = errno;                /* save error code */
3068 #ifdef TCPIPLIB
3069                 socket_close(tcpsrfd);
3070 #else /* TCPIPLIB */
3071                 close(tcpsrfd);
3072 #endif /* TCPIPLIB */
3073                 ttyfd = -1;
3074                 wasclosed = 1;
3075                 tcpsrfd = -1;
3076                 tcpsrv_port = 0;
3077                 errno = i;                /* and report this error */
3078                 debug(F101,"tcpsrv_open accept errno","",errno);
3079                 return(-1);
3080             }
3081         }
3082 #endif /* KRB5_U2U */
3083 #endif /* CK_KERBEROS */
3084         return(0);                      /* Done. */
3085     } else {
3086         i = errno;                      /* save error code */
3087 #ifdef TCPIPLIB
3088         socket_close(tcpsrfd);
3089 #else /* TCPIPLIB */
3090         close(tcpsrfd);
3091 #endif /* TCPIPLIB */
3092         ttyfd = -1;
3093         wasclosed = 1;
3094         tcpsrfd = -1;
3095         tcpsrv_port = 0;
3096         errno = i;                      /* and report this error */
3097         debug(F101,"tcpsrv_open accept errno","",errno);
3098         return(-1);
3099     }
3100 }
3101 #endif /* NOLISTEN */
3102 #endif /* OS2 */
3103 #endif /* TCPSOCKET */
3104 #endif /* NONET */
3105
3106 #ifdef TCPSOCKET
3107 char *
3108 ckname2addr(name) char * name;
3109 {
3110 #ifdef HPUX5
3111     return("");
3112 #else
3113     struct hostent *host;
3114
3115     if (name == NULL || *name == '\0')
3116         return("");
3117
3118     host = gethostbyname(name);
3119     if ( host ) {
3120         host = ck_copyhostent(host);
3121         return(inet_ntoa(*((struct in_addr *) host->h_addr)));
3122     }
3123     return("");
3124 #endif /* HPUX5 */
3125 }
3126
3127 char *
3128 ckaddr2name(addr) char * addr;
3129 {
3130 #ifdef HPUX5
3131     return("");
3132 #else
3133     struct hostent *host;
3134     struct in_addr sin_addr;
3135
3136     if (addr == NULL || *addr == '\0')
3137         return("");
3138
3139     sin_addr.s_addr = inet_addr(addr);
3140     host = gethostbyaddr((char *)&sin_addr,4,AF_INET);
3141     if (host) {
3142         host = ck_copyhostent(host);
3143         return((char *)host->h_name);
3144     }
3145     return("");
3146 #endif /* HPUX5 */
3147 }
3148 #endif /* TCPSOCKET */
3149
3150 unsigned long peerxipaddr = 0L;
3151
3152 char *
3153 ckgetpeer() {
3154 #ifdef TCPSOCKET
3155     static char namebuf[256];
3156     static struct hostent *host;
3157     static struct sockaddr_in saddr;
3158 #ifdef GPEERNAME_T
3159     static GPEERNAME_T saddrlen;
3160 #else
3161 #ifdef PTX
3162     static size_t saddrlen;
3163 #else
3164 #ifdef AIX42
3165     /* It's size_t in 4.2 but int in 4.1 and earlier. */
3166     /* Note: the 4.2 man page lies; believe socket.h. */
3167     static size_t saddrlen;
3168 #else
3169 #ifdef UNIXWARE
3170     static size_t saddrlen;
3171 #else  /* UNIXWARE */
3172 #ifdef DEC_TCPIP
3173 /* 2010-03-08 SMS.
3174  * Coincidentally, the condition for integer arguments in select(),
3175  * which is actually "defined( _DECC_V4_SOURCE)", works for an integer
3176  * argument in getpeername().  Sadly, due to a lack of foresight,
3177  * "defined( _DECC_V4_SOURCE)" doesn't work with DEC C V4.0, so the
3178  * user-specified INTSELECT is used instead.  Most likely, "size_t"
3179  * should be used instead of "unsigned int", but I'm a coward.
3180  */
3181 #ifdef INTSELECT
3182     static int saddrlen;
3183 #else /* def INTSELECT */
3184     static unsigned int saddrlen;
3185 #endif /* def INTSELECT [else] */
3186 #else
3187 #ifdef MACOSX10
3188     static unsigned int saddrlen;
3189 #else
3190 #ifdef CK_64BIT
3191     static socklen_t saddrlen;
3192 #else
3193     static int saddrlen;
3194 #endif  /* CK_64BIT */
3195 #endif /* MACOSX10 */
3196 #endif /* DEC_TCPIP */
3197 #endif /* UNIXWARE */
3198 #endif /* AIX42 */
3199 #endif /* PTX */
3200 #endif  /* GPEERNAME_T */
3201     saddrlen = sizeof(saddr);
3202     if (getpeername(ttyfd,(struct sockaddr *)&saddr,&saddrlen) < 0) {
3203         debug(F111,"ckgetpeer failure",ckitoa(ttyfd),errno);
3204         return(NULL);
3205     }
3206     host = gethostbyaddr((char *)&saddr.sin_addr,4,AF_INET);
3207     if (host) {
3208         host = ck_copyhostent(host);
3209         ckstrncpy(namebuf,(char *)host->h_name,80);
3210     } else {
3211         ckstrncpy(namebuf,(char *)inet_ntoa(saddr.sin_addr),80);
3212     }
3213     peerxipaddr = ntohl(saddr.sin_addr.s_addr);
3214     debug(F111,"ckgetpeer",namebuf,peerxipaddr);
3215     return(namebuf);
3216 #else
3217     return(NULL);
3218 #endif /* TCPSOCKET */
3219 }
3220
3221 /* Get fully qualified IP hostname */
3222
3223 #ifndef NONET
3224 char *
3225 #ifdef CK_ANSIC
3226 ckgetfqhostname(char * name)
3227 #else
3228 ckgetfqhostname(name) char * name;
3229 #endif /* CK_ANSIC */
3230 {
3231 #ifdef NOCKGETFQHOST
3232
3233     return(name);
3234
3235 #else /* If the following code dumps core, define NOCKGETFQHOST and rebuild. */
3236
3237     static char namebuf[256];
3238     struct hostent *host=NULL;
3239     struct sockaddr_in r_addr;
3240     int i;
3241
3242     debug(F110,"ckgetfqhn()",name,0);
3243
3244     ckstrncpy(namebuf,name,256);
3245     namebuf[255] = '\0';
3246     i = ckindex(":",namebuf,0,0,0);
3247     if (i)
3248       namebuf[i-1] = '\0';
3249
3250     bzero((char *)&r_addr, sizeof(r_addr));
3251
3252     host = gethostbyname(namebuf);
3253     if (host) {
3254         host = ck_copyhostent(host);
3255         debug(F100,"ckgetfqhn() gethostbyname != NULL","",0);
3256         r_addr.sin_family = host->h_addrtype;
3257 #ifdef HADDRLIST
3258 #ifdef h_addr
3259         /* This is for trying multiple IP addresses - see <netdb.h> */
3260         if (!(host->h_addr_list))
3261           goto exit_func;
3262         bcopy(host->h_addr_list[0],
3263               (caddr_t)&r_addr.sin_addr,
3264               host->h_length
3265               );
3266 #else
3267         bcopy(host->h_addr, (caddr_t)&r_addr.sin_addr, host->h_length);
3268 #endif /* h_addr */
3269 #else  /* HADDRLIST */
3270         bcopy(host->h_addr, (caddr_t)&r_addr.sin_addr, host->h_length);
3271 #endif /* HADDRLIST */
3272 #ifdef COMMENT
3273 #ifndef EXCELAN
3274         debug(F111,"BCOPY","host->h_addr",host->h_addr);
3275 #endif /* EXCELAN */
3276         debug(F111,"BCOPY"," (caddr_t)&r_addr.sin_addr",
3277               (caddr_t)&r_addr.sin_addr);
3278 #endif  /* COMMENT */
3279         debug(F111,"BCOPY","host->h_length",host->h_length);
3280
3281 #ifdef NT
3282         /* Windows 95/98 requires a 1 second wait between calls to Microsoft */
3283         /* provided DNS functions.  Otherwise, the TTL of the DNS response */
3284         /* is ignored. */
3285         if (isWin95())
3286           sleep(1);
3287 #endif /* NT */
3288         host = gethostbyaddr((char *)&r_addr.sin_addr,4,PF_INET);
3289         if (host) {
3290             host = ck_copyhostent(host);
3291             debug(F100,"ckgetfqhn() gethostbyaddr != NULL","",0);
3292             ckstrncpy(namebuf, host->h_name, 256);
3293         }
3294     }
3295
3296 #ifdef HADDRLIST
3297 #ifdef h_addr
3298   exit_func:
3299 #endif /* h_addr */
3300 #endif /* HADDRLIST */
3301
3302     if (i > 0)
3303       ckstrncat(namebuf,&name[i-1],256-strlen(namebuf)-strlen(&name[i-1]));
3304     debug(F110,"ckgetfqhn()",namebuf,0);
3305     return(namebuf);
3306 #endif /* NOCKGETFQHOST */
3307 }
3308
3309 VOID
3310 #ifdef CK_ANSIC
3311 setnproto(char * p)
3312 #else
3313 setnproto(p) char * p;
3314 #endif /* CK_ANSIC */
3315 {
3316     if (!isdigit(*p)) {
3317         if (!strcmp("kermit",p))
3318           ttnproto = NP_KERMIT;
3319         else if (!strcmp("telnet",p))
3320           ttnproto = NP_TELNET;
3321         else if (!strcmp("http",p))
3322           ttnproto = NP_TCPRAW;
3323 #ifdef RLOGCODE
3324         else if (!strcmp("login",p))
3325           ttnproto = NP_RLOGIN;
3326 #endif /* RLOGCODE */
3327 #ifdef CK_SSL
3328         /* Commonly used SSL ports (might not be in services file) */
3329         else if (!strcmp("https",p)) {
3330           ttnproto = NP_SSL_RAW;
3331           ssl_only_flag = 1;
3332         } else if (!strcmp("ssl-telnet",p)) {
3333           ttnproto = NP_TELNET;
3334           ssl_only_flag = 1;
3335         } else if (!strcmp("telnets",p)) {
3336           ttnproto = NP_TELNET;
3337           ssl_only_flag = 1;
3338         }
3339 #endif /* CK_SSL */
3340 #ifdef CK_KERBEROS
3341 #ifdef RLOGCODE
3342         else if (!strcmp("klogin",p)) {
3343             if (ck_krb5_is_installed())
3344               ttnproto = NP_K5LOGIN;
3345             else if (ck_krb4_is_installed())
3346               ttnproto = NP_K4LOGIN;
3347             else
3348               ttnproto = NP_RLOGIN;
3349         } else if (!strcmp("eklogin",p)) {
3350             if (ck_krb5_is_installed())
3351               ttnproto = NP_EK5LOGIN;
3352             else if (ck_krb4_is_installed())
3353               ttnproto = NP_EK4LOGIN;
3354             else
3355               ttnproto = NP_RLOGIN;
3356         }
3357 #endif /* RLOGCODE */
3358 #endif /* CK_KERBEROS */
3359         else
3360           ttnproto = NP_NONE;
3361     } else {
3362         switch (atoi(p)) {
3363           case 23:                      /* Telnet */
3364             ttnproto = NP_TELNET;
3365             break;
3366           case 513:
3367             ttnproto = NP_RLOGIN;
3368             break;
3369           case 1649:
3370             ttnproto = NP_KERMIT;
3371             break;
3372 #ifdef CK_SSL
3373           case 443:
3374 #ifdef COMMENT
3375             /* Jeff 2005/12/30 */
3376             ttnproto = NP_SSL_RAW;
3377 #else
3378             /* fdc 2005/12/04 */
3379             ttnproto = NP_SSL;
3380 #endif  /* COMMENT */
3381             ssl_only_flag = 1;
3382             break;
3383           case 151:
3384           case 992:
3385             ttnproto = NP_TELNET;
3386             ssl_only_flag = 1;
3387             break;
3388 #endif /* CK_SSL */
3389 #ifdef CK_KERBEROS
3390           case 543:
3391             if (ck_krb5_is_installed())
3392               ttnproto = NP_K5LOGIN;
3393             else if (ck_krb4_is_installed())
3394               ttnproto = NP_K4LOGIN;
3395             else
3396               ttnproto = NP_RLOGIN;
3397             break;
3398           case 2105:
3399             if (ck_krb5_is_installed())
3400               ttnproto = NP_EK5LOGIN;
3401             else if (ck_krb4_is_installed())
3402               ttnproto = NP_EK4LOGIN;
3403             else
3404               ttnproto = NP_RLOGIN;
3405             break;
3406 #endif /* CK_KERBEROS */
3407           case 80:                      /* HTTP */
3408             ttnproto = NP_TCPRAW;
3409             break;
3410           default:
3411             ttnproto = NP_NONE;
3412             break;
3413         }
3414     }
3415 }
3416
3417 /* ckgetservice() is used to determine the port number for a given */
3418 /* service taking into account the use of DNS SRV records.         */
3419
3420 static struct servent servrec;
3421 static struct servent *
3422 ckgetservice(hostname, servicename, ip, iplen)
3423     char *hostname; char * servicename; char * ip; int iplen;
3424 {
3425     struct servent * service = NULL;
3426 #ifdef CK_DNS_SRV
3427     struct sockaddr * dns_addrs = NULL;
3428     int dns_naddrs = 0;
3429 #endif /* CK_DNS_SRV */
3430
3431     if (isdigit(*servicename)) {        /* Use socket number without lookup */
3432         service = &servrec;
3433         service->s_port = htons((unsigned short)atoi(servicename));
3434     } else {                            /* Otherwise lookup the service name */
3435 #ifdef CK_DNS_SRV
3436         if (tcp_dns_srv && !quiet) {
3437             printf(" DNS SRV Lookup... ");
3438             fflush(stdout);
3439         }
3440         if (tcp_dns_srv &&
3441             locate_srv_dns(hostname,
3442                            servicename,
3443                            "tcp",
3444                            &dns_addrs,
3445                            &dns_naddrs
3446                            )
3447             ) {
3448             /* Use the first one.  Eventually we should cycle through all */
3449             /* the returned IP addresses and port numbers. */
3450             struct sockaddr_in *sin = NULL;
3451 #ifdef BETADEBUG
3452             int i;
3453             printf("\r\n");
3454             for ( i=0;i<dns_naddrs;i++ ) {
3455                 sin = (struct sockaddr_in *) &dns_addrs[i];
3456                 printf("dns_addrs[%d] = %s %d\r\n", i,
3457                         (char *)inet_ntoa(sin->sin_addr),
3458                         ntohs(sin->sin_port));
3459             }
3460 #endif /* BETADEBUG */
3461             sin = (struct sockaddr_in *) &dns_addrs[0];
3462             if ( ip && iplen > 0 )
3463                 ckstrncpy(ip,(char *)inet_ntoa(sin->sin_addr),iplen);
3464             service = &servrec;
3465             service->s_port = sin->sin_port;
3466
3467             free(dns_addrs);
3468             dns_addrs = NULL;
3469             dns_naddrs = 0;
3470         } else
3471 #endif /* CK_DNS_SRV */
3472             service = getservbyname(servicename, "tcp");
3473     }
3474     if (!service) {
3475         if (!ckstrcmp("kermit",servicename,-1,0)) { /* Kermit service port */
3476             service = &servrec;
3477             service->s_port = htons(1649);
3478         } else if (!ckstrcmp("telnet",servicename,-1,0)) { /* Telnet port */
3479             service = &servrec;
3480             service->s_port = htons(23);
3481         } else if (!ckstrcmp("http",servicename,-1,0)) {
3482             service = &servrec;
3483             service->s_port = htons(80);
3484         }
3485 #ifdef RLOGCODE
3486         else if (!ckstrcmp("login",servicename,-1,0)) {
3487             service = &servrec;
3488             service->s_port = htons(513);
3489         }
3490 #endif /* RLOGCODE */
3491 #ifdef CK_SSL
3492         /* Commonly used SSL ports (might not be in services file) */
3493         else if (!ckstrcmp("https",servicename,-1,0)) {
3494             service = &servrec;
3495             service->s_port = htons(443);
3496         } else if (!ckstrcmp("ssl-telnet",servicename,-1,0)) {
3497             service = &servrec;
3498             service->s_port = htons(151);
3499         } else if (!ckstrcmp("telnets",servicename,-1,0)) {
3500             service = &servrec;
3501             service->s_port = htons(992);
3502         }
3503 #endif /* CK_SSL */
3504 #ifdef CK_KERBEROS
3505 #ifdef RLOGCODE
3506         else if (!ckstrcmp("klogin",servicename,-1,0)) {
3507             service = &servrec;
3508             service->s_port = htons(543);
3509         } else if (!ckstrcmp("eklogin",servicename,-1,0)) {
3510             service = &servrec;
3511             service->s_port = htons(2105);
3512         }
3513 #endif /* RLOGCODE */
3514 #endif /* CK_KERBEROS */
3515     }
3516     return(service);
3517 }
3518
3519 /*  N E T O P E N  --  Open a network connection  */
3520 /*
3521   Calling conventions same as ttopen(), except third argument is network
3522   type rather than modem type.  Designed to be called from within ttopen.
3523 */
3524
3525 #define XXNAMELEN 256
3526 static char xxname[XXNAMELEN];
3527
3528 int
3529 netopen(name, lcl, nett) char *name; int *lcl, nett; {
3530     char *p;
3531     int i, x, rc_inet_addr = 0, dns = 0;
3532 #ifdef TCPSOCKET
3533     int isconnect = 0;
3534 #ifdef SO_OOBINLINE
3535     int on = 1;
3536 #endif /* SO_OOBINLINE */
3537     struct servent *service=NULL;
3538     struct hostent *host=NULL;
3539     struct sockaddr_in r_addr;
3540     struct sockaddr_in sin;
3541     struct sockaddr_in l_addr;
3542     GSOCKNAME_T l_slen;
3543 #ifdef EXCELAN
3544     struct sockaddr_in send_socket;
3545 #endif /* EXCELAN */
3546
3547 #ifdef INADDRX
3548 /* inet_addr() is of type struct in_addr */
3549 #ifdef datageneral
3550     extern struct in_addr inet_addr();
3551 #else
3552 #ifdef HPUX5WINTCP
3553     extern struct in_addr inet_addr();
3554 #endif /* HPUX5WINTCP */
3555 #endif /* datageneral */
3556     struct in_addr iax;
3557 #else
3558 #ifdef INADDR_NONE
3559     struct in_addr iax;
3560 #else /* INADDR_NONE */
3561     long iax;
3562 #endif /* INADDR_NONE */
3563 #endif /* INADDRX */
3564 #endif /* TCPSOCKET */
3565
3566 #ifdef COMMENT
3567 /* This causes big trouble */
3568 #ifndef INADDR_NONE
3569 #define INADDR_NONE 0xffffffff
3570 #endif /* INADDR_NONE */
3571 #endif /* COMMENT */
3572
3573 #ifdef SUNX25                           /* Code for SunLink X.25 support */
3574 #define X29PID 1                        /* X.29 Protocol ID */
3575 _PROTOTYP(SIGTYP x25oobh, (int) );
3576     CONN_DB x25host;
3577 #ifndef X25_WR_FACILITY
3578     FACILITY x25facil;
3579 #else
3580     FACILITY_DB x25facil;
3581 #endif /* X25_WR_FACILITY */
3582     static int needh = 1;
3583     PID_T pid;
3584     extern int linkid, lcn, x25ver;
3585 #endif /* SUNX25 */
3586 #ifdef ANYX25
3587     extern int revcall, closgr, cudata;
3588     extern char udata[];
3589 #endif /* ANYX25 */
3590
3591 #ifdef IBMX25                           /* Variables for IBM X25 */
3592     extern int x25port;                 /* Logical port to use */
3593     extern x25addr_t local_nua;         /* Local X.25 address */
3594     extern x25addr_t remote_nua;        /* Remote X.25 address */
3595     extern char x25name[];              /* X25 device name (sx25a0) */
3596     extern char x25dev[];               /* X25 device file /dev/x25pkt */
3597     ulong bind_flags = 0;               /* Flags for binding the X25 stream */
3598     ulong token = 0;                    /* Temporary return code */
3599 #endif /* IBMX25 */
3600
3601     debug(F101,"netopen nett","",nett);
3602     *ipaddr = '\0';                     /* Initialize IP address string */
3603
3604 #ifdef SUNX25
3605     if (nett == NET_SX25) {             /* If network type is X.25 */
3606         netclos();                      /* Close any previous net connection */
3607         ttnproto = NP_NONE;             /* No protocol selected yet */
3608
3609         /* Set up host structure */
3610         bzero((char *)&x25host,sizeof(x25host));
3611         if ((x25host.hostlen = pkx121(name,x25host.host)) < 0) {
3612             fprintf (stderr,"Invalid X.121 host address %s\n",name);
3613             errno = 0;
3614             return (-1);
3615         }
3616         x25host.datalen = X29PIDLEN;
3617         x25host.data[0] = X29PID;
3618
3619         /* Set call user data if specified */
3620         if (cudata) {
3621             ckstrncpy((char *)x25host.data+X29PIDLEN,udata,(int)strlen(udata));
3622             x25host.datalen += (int)strlen(udata);
3623         }
3624
3625         /* Open SunLink X.25 socket */
3626         if (!quiet && *name) {
3627             printf(" Trying %s... ", name);
3628             fflush(stdout);
3629         }
3630         if ((ttyfd = socket(AF_X25, SOCK_STREAM, 0)) < 0) {
3631             debug(F101,"netopen socket error","",errno);
3632             perror ("X.25 socket error");
3633             return (-1);
3634         }
3635
3636         /* Setting X.25 out-of-band data handler */
3637         pid = getpid();
3638         if (ioctl(ttyfd,SIOCSPGRP,&pid)) {
3639             perror("X.25 set process group id error");
3640             return(-1);
3641         }
3642         (VOID) signal(SIGURG,x25oobh);
3643
3644         /* Set reverse charge call and closed user group if requested */
3645         bzero ((char *)&x25facil,sizeof(x25facil));
3646
3647 #ifndef X25_WR_FACILITY
3648 /*  New SunLink (7.0 or 8.0, not sure which)... */
3649         x25facil.type = T_REVERSE_CHARGE; /* Reverse Charge */
3650         x25facil.f_reverse_charge = revcall ? 1 : 0;
3651         if (ioctl(ttyfd,X25_SET_FACILITY,&x25facil) < 0) {
3652             perror ("Setting X.25 reverse charge");
3653             return (-1);
3654         }
3655         if (closgr > -1) {              /* Closed User Group (Outgoing) */
3656             bzero ((char *)&x25facil,sizeof(x25facil));
3657             x25facil.type = T_CUG;
3658             x25facil.f_cug_req = CUG_REQ_ACS;
3659             x25facil.f_cug_index = closgr;
3660             if (ioctl(ttyfd,X25_SET_FACILITY,&x25facil) < 0) {
3661                 perror ("Setting X.25 closed user group");
3662                 return (-1);
3663             }
3664         }
3665 #else
3666 /*  Old SunLink 6.0 (or 7.0?)... */
3667         if (revcall) x25facil.reverse_charge = revcall;
3668         if (closgr > -1) {
3669             x25facil.cug_req = 1;
3670             x25facil.cug_index = closgr;
3671         }
3672         if (ioctl(ttyfd,X25_WR_FACILITY,&x25facil) < 0) {
3673             perror ("Setting X.25 facilities");
3674             return (-1);
3675         }
3676 #endif /* X25_WR_FACILITY */
3677
3678         /*  Need X.25 header with bits Q and M */
3679         if (ioctl (ttyfd,X25_HEADER,&needh) < 0) {
3680             perror ("Setting X.25 header");
3681             return (-1);
3682         }
3683
3684         /* Connects to remote host via SunLink X.25 */
3685         if (connect(ttyfd,(struct sockaddr *)&x25host,sizeof(x25host)) < 0) {
3686             i = errno;
3687             debug(F101,"netopen connect errno","",i);
3688             if (i) {
3689                 perror("netopen x25 connect");
3690                 x25diag();
3691             }
3692             (VOID) netclos();
3693             ttyfd = -1;
3694             wasclosed = 1;
3695             ttnproto = NP_NONE;
3696             errno = i;
3697             return (-1);
3698         }
3699
3700         /* Get X.25 link identification used for the connection */
3701         if (ioctl(ttyfd,X25_GET_LINK,&linkid) < 0) {
3702             perror ("Getting X.25 link id");
3703             return (-1);
3704         }
3705
3706         /* Get X.25 logical channel number used for the connection */
3707         if (ioctl(ttyfd,X25_RD_LCGN,&lcn) < 0) {
3708             perror ("Getting X.25 lcn");
3709             return (-1);
3710         }
3711
3712         /* Get SunLink X.25 version */
3713         if (ioctl(ttyfd,X25_VERSION,&x25ver) < 0) {
3714             perror ("Getting SunLink X.25 version");
3715             return (-1);
3716         }
3717         ttnet = nett;                   /* Sunlink X.25 network */
3718         ttnproto = NP_X3;               /* PAD X.3, X.28, X.29 protocol */
3719         if (lcl) if (*lcl < 0) *lcl = 1; /* Local mode */
3720         return(0);
3721     } else /* Note that SUNX25 support can coexist with TCP/IP support. */
3722 #endif /* SUNX25 */
3723
3724 #ifdef IBMX25
3725     /* riehm */
3726     if (nett == NET_IX25) {             /* IBM AIX X.25 */
3727         netclos();                      /* Close any previous net connection */
3728         ttnproto = NP_NONE;             /* No protocol selected yet */
3729
3730         /* find out who we are - this is not so easy on AIX */
3731         /* riehm: need to write the code that finds this out
3732          * automatically, or at least allow it to be configured
3733          * somehow
3734          */
3735         if (!local_nua[0] && !x25local_nua(local_nua)) {
3736             return(-1);
3737         }
3738
3739         /* Initialise the X25 API (once per process? once per connection?) */
3740
3741         debug(F110, "Opening ", x25dev, 0 );
3742         /* set O_NDELAY to allow polling? */
3743         if ((ttyfd = open(x25dev, O_RDWR)) < 0) {
3744             perror ("X.25 device open error");
3745             debug(F101,"netopen: device open error","",errno);
3746             return (-1);
3747         }
3748
3749         /* push the NPI onto the STREAM */
3750         if (ioctl(ttyfd,I_PUSH,"npi") < 0 ) {
3751             close(ttyfd);
3752             ttyfd = -1;
3753             wasclosed = 1;
3754             perror( "kermit: netopen(): couldn't push npi on the X25 stream" );
3755             debug(F101,"netopen: can't push npi on the X25 stream","",errno);
3756             return (-1);
3757         }
3758
3759         /* set up server mode - bind the x25 port and wait for
3760          * incoming connections
3761          */
3762         if (name[0] == '*') {           /* Server */
3763             /* set up a server - see the warning in x25bind() */
3764             bind_flags |= TOKEN_REQUEST;
3765
3766             /* bind kermit to the local X25 address */
3767             token = x25bind(ttyfd,
3768                             local_nua,
3769                             udata,
3770                             (int)strlen( udata ),
3771                             1,
3772                             x25port,
3773                             bind_flags
3774                             );
3775             if (token < 0) {
3776                 debug(F100,"netopen: couldn't bind to local X25 address","",0);
3777                 netclos();
3778                 return(-1);
3779             }
3780             /* Currently not connected to a remote host */
3781
3782             remote_nua[0] = '\0';
3783
3784             /* store the fd so that incoming calls can have their own fd
3785              * This is almost support for a true server (ie: a'la ftpd)
3786              * but we're not quite there yet.
3787              * used in netclos()
3788              */
3789             x25serverfd = ttyfd;
3790             /*
3791              * wait for an incoming call
3792              * this should happen in the "server" command and not in
3793              * the "set host *" command.
3794              */
3795             if ((ttyfd = x25getcall(ttyfd)) < 0) {
3796                 netclos();
3797                 return(-1);
3798             }
3799         } else {                        /* Client */
3800             /* Bind kermit to the local X25 address */
3801             token = x25bind(
3802                             ttyfd,
3803                             local_nua,
3804                             (char *)NULL,
3805                             0,
3806                             0,
3807                             x25port,
3808                             bind_flags
3809                             );
3810             if (token < 0) {
3811                 debug(F100,"netopen: couldn't bind to local X25 address","",0);
3812                 netclos();
3813                 return(-1);
3814             }
3815 /* riehm: this should be done via the CONNECT command, not HOST! */
3816             {
3817                 x25serverfd = 0;
3818                 /* call the remote host */
3819                 /* name == address of remote host as char* */
3820                 if (x25call(ttyfd, name, udata) < 0 ) {
3821                     debug(F100,
3822                           "netopen: couldn't connect to remote X25 address",
3823                           "", 0);
3824                     netclos();
3825                     return(-1);
3826                 }
3827                 strcpy(remote_nua, name);
3828             }
3829         }
3830         ttnet = nett;                   /* AIX X.25 network */
3831         if (lcl) if (*lcl < 0) *lcl = 1; /* Local mode */
3832         return(0);
3833
3834     } else /* Note that IBMX25 support can coexist with TCP/IP support. */
3835 #endif /* IBMX25 */
3836
3837 /*   Add support for other networks here. */
3838
3839       if (nett != NET_TCPB) return(-1); /* BSD socket support */
3840
3841 #ifdef TCPSOCKET
3842     netclos();                          /* Close any previous connection. */
3843     ckstrncpy(namecopy, name, NAMECPYL);        /* Copy the hostname. */
3844     debug(F110,"netopen namecopy",namecopy,0);
3845
3846 #ifndef NOLISTEN
3847     if (name[0] == '*')
3848       return(tcpsrv_open(name, lcl, nett, 0));
3849 #endif /* NOLISTEN */
3850
3851     p = namecopy;                       /* Was a service requested? */
3852     while (*p != '\0' && *p != ':') p++; /* Look for colon */
3853     if (*p == ':') {                    /* Have a colon */
3854         debug(F110,"netopen name has colon",namecopy,0);
3855         *p++ = '\0';                    /* Get service name or number */
3856 #ifdef CK_URL
3857         /*
3858            Here we have to check for various popular syntaxes:
3859            host:port (our original syntax)
3860            URL such as telnet:host or telnet://host/
3861            Or even telnet://user:password@host:port/path/
3862            Or a malformed URL such as generated by Netscape 4.0 like:
3863            telnet:telnet or telnet::host.
3864         */
3865
3866         /*
3867          * REPLACE THIS CODE WITH urlparse() but not on the day of the
3868          * C-Kermit 8.0 RELEASE.
3869          */
3870
3871         if (*p == ':')                  /* a second colon */
3872           *p++ = '\0';                  /* get rid of that one too */
3873         while (*p == '/') *p++ = '\0';  /* and slashes */
3874         x = strlen(p);                  /* Length of remainder */
3875         if (p[x-1] == '/')              /* If there is a trailing slash */
3876           p[x-1] = '\0';                /* remove it. */
3877         debug(F110,"netopen namecopy after stripping",namecopy,0);
3878         debug(F110,"netopen p after stripping",p,0);
3879         service = getservbyname(namecopy,"tcp");
3880         if (service ||
3881 #ifdef RLOGCODE
3882             !ckstrcmp("rlogin",namecopy,NAMECPYL,0) ||
3883 #endif /* RLOGCODE */
3884 #ifdef CK_SSL
3885             !ckstrcmp("telnets",namecopy,NAMECPYL,0) ||
3886 #endif /* CK_SSL */
3887             !ckstrcmp("iksd",namecopy,NAMECPYL,0)
3888             ) {
3889             char temphost[256], tempservice[80], temppath[256];
3890             char * q = p, *r = p, *w = p;
3891             int uidfound=0;
3892             extern char pwbuf[];
3893             extern int pwflg, pwcrypt;
3894
3895             if (ttnproto == NP_DEFAULT)
3896               setnproto(namecopy);
3897
3898             /* Check for userid and possibly password */
3899             while (*p != '\0' && *p != '@')
3900                 p++; /* look for @ */
3901             if (*p == '@') {
3902                 /* found username and perhaps password */
3903                 debug(F110,"netopen namecopy found @","",0);
3904                 *p = '\0';
3905                 p++;
3906                 while (*w != '\0' && *w != ':')
3907                   w++;
3908                 if (*w == ':')
3909                   *w++ = '\0';
3910                 /* r now points to username, save it and the password */
3911                 debug(F110,"netopen namecopy username",r,0);
3912                 debug(F110,"netopen namecopy password",w,0);
3913                 uidfound=1;
3914                 if ( strcmp(uidbuf,r) || *w )
3915                     ckstrncpy(pwbuf,w,PWBUFL+1);
3916                 ckstrncpy(uidbuf,r,UIDBUFLEN);
3917                 pwflg = 1;
3918                 pwcrypt = 0;
3919                 q = p;                  /* Host after user and pwd */
3920             } else {
3921                 p = q;                  /* No username or password */
3922             }
3923             /* Now we must look for the optional port. */
3924             debug(F110,"netopen x p",p,0);
3925             debug(F110,"netopen x q",q,0);
3926
3927             /* Look for the port/service or a file/directory path */
3928             while (*p != '\0' && *p != ':' && *p != '/')
3929               p++;
3930             if (*p == ':') {
3931                 debug(F110,"netopen found port",q,0);
3932                 *p++ = '\0';            /* Found a port name or number */
3933                 r = p;
3934
3935                 /* Look for the end of port/service or a file/directory path */
3936                 while (*p != '\0' && *p != '/')
3937                     p++;
3938                 if (*p == '/')
3939                     *p++ = '\0';
3940
3941                 debug(F110,"netopen port",r,0);
3942                 ckstrncpy(tempservice,r,80);
3943                 ckstrncpy(temphost,q,256);
3944                 ckstrncpy(temppath,p,256);
3945                 ckstrncpy(namecopy,temphost,NAMECPYL);
3946                 debug(F110,"netopen tempservice",tempservice,0);
3947                 debug(F110,"netopen temphost",temphost,0);
3948                 debug(F110,"netopen temppath",temppath,0);
3949
3950                 /* move port/service to a buffer that won't go away */
3951                 x = strlen(namecopy);
3952                 p = namecopy + x + 1;
3953                 ckstrncpy(p, tempservice, NAMECPYL - x);
3954             } else {
3955                 /* Handle a path if we found one */
3956                 if (*p == '/')
3957                     *p++ = '\0';
3958                 ckstrncpy(temppath,p,256);
3959
3960                 /* We didn't find another port, but if q is a service */
3961                 /* then assume that namecopy is actually a host.      */
3962                 if (getservbyname(q,"tcp")) {
3963                     p = q;
3964                 } else {
3965 #ifdef RLOGCODE
3966                     /* rlogin is not a valid service */
3967                     if (!ckstrcmp("rlogin",namecopy,6,0)) {
3968                         ckstrncpy(namecopy,"login",NAMECPYL);
3969                     }
3970 #endif /* RLOGCODE */
3971                     /* iksd is not a valid service */
3972                     if (!ckstrcmp("iksd",namecopy,6,0)) {
3973                         ckstrncpy(namecopy,"kermit",NAMECPYL);
3974                     }
3975                     /* Reconstruct namecopy */
3976                     ckstrncpy(tempservice,namecopy,80);
3977                     ckstrncpy(temphost,q,256);
3978                     ckstrncpy(namecopy,temphost,NAMECPYL);
3979                     debug(F110,"netopen tempservice",tempservice,0);
3980                     debug(F110,"netopen temphost",temphost,0);
3981                     debug(F110,"netopen temppath",temppath,0);
3982
3983                     /* move port/service to a buffer that won't go away */
3984                     x = strlen(namecopy);
3985                     p = namecopy + x + 1;
3986                     ckstrncpy(p, tempservice, NAMECPYL - x - 1);
3987                 }
3988             }
3989             debug(F110,"netopen URL result: host",namecopy,0);
3990             debug(F110,"netopen URL result: service",p,0);
3991             debug(F110,"netopen URL result: path",temppath,0);
3992
3993 #ifdef IKS_GET
3994             /* If we have set a path specified, we need to try to GET it */
3995             /* But we have another problem, we have to login first.  How */
3996             /* do we specify that a login must be done before the GET?   */
3997             /* The user's name if specified is in 'userid' and the       */
3998             /* password if any is in 'pwbuf'.                            */
3999             if ( temppath[0] ) {
4000                 extern int action;
4001                 extern char * cmarg;
4002
4003                 if ( !uidfound ) {
4004                     /* If no userid was specified as part of the URL but
4005                      * a path was specified, then we
4006                      * set the user name to anonymous and the password
4007                      * to the current userid.
4008                      */
4009                     ckstrncpy(pwbuf,uidbuf,PWBUFL);
4010                     ckstrncat(pwbuf,"@",PWBUFL);
4011                     pwflg = 1;
4012                     pwcrypt = 0;
4013                     ckstrncpy(uidbuf,"anonymous",UIDBUFLEN);
4014                 }
4015
4016                 /*
4017                  * If a file path was specified we perform the GET
4018                  * operation and then terminate the connection.
4019                  *
4020                  * If a directory was given instead of a file, then
4021                  * we should REMOTE CD to the directory and list its
4022                  * contents.  But how do we tell the difference?
4023                  */
4024                 makestr(&cmarg,temppath);
4025                 action = 'r';
4026             }
4027 #endif /* IKS_GET */
4028         }
4029 #endif /* CK_URL */
4030     } else {                            /* Otherwise use telnet */
4031         p = "telnet";
4032     }
4033 /*
4034   By the time we get here, namecopy[] should hold the null-terminated
4035   hostname or address, and p should point to the service name or number.
4036 */
4037     debug(F110,"netopen host",namecopy,0);
4038     debug(F110,"netopen service requested",p,0);
4039
4040    /* Use the service port to set the default protocol type if necessary */
4041     if (ttnproto == NP_DEFAULT)
4042        setnproto(p);
4043
4044     ckstrncpy(namecopy2,namecopy,NAMECPYL);
4045     service = ckgetservice(namecopy,p,namecopy,NAMECPYL);
4046     if (!service) {
4047         fprintf(stderr, "Can't find port for service %s\n", p);
4048 #ifdef TGVORWIN
4049         debug(F101,"netopen can't get service","",socket_errno);
4050 #else
4051         debug(F101,"netopen can't get service","",errno);
4052 #endif /* TGVORWIN */
4053         errno = 0;                  /* (rather than mislead) */
4054         return(-1);
4055     } else {
4056         if (!ckstrcmp(namecopy,namecopy2,-1,0))
4057           namecopy2[0] = '\0';
4058         ckstrncpy(svcbuf,ckuitoa(ntohs(service->s_port)),sizeof(svcbuf));
4059         debug(F110,"netopen service ok",svcbuf,0);
4060     }
4061
4062 #ifdef RLOGCODE
4063     if (service && !strcmp("login",p) && service->s_port != htons(513)) {
4064         fprintf(stderr,
4065                 "  Warning: login service on port %d instead of port 513\n",
4066                  ntohs(service->s_port)
4067                 );
4068         fprintf(stderr, "  Edit SERVICES file if RLOGIN fails to connect.\n");
4069         debug(F101,"tcpsrv_open login on port","",ntohs(service->s_port));
4070     }
4071 #endif /* RLOGCODE */
4072
4073 #ifndef NOHTTP
4074    /* For HTTP connections we must preserve the original hostname and */
4075    /* service requested so we can include them in the Host header.    */
4076     ckmakmsg(http_host_port,sizeof(http_host_port),namecopy,":",
4077               ckitoa(ntohs(service->s_port)),NULL);
4078
4079     /* 'namecopy' contains the name of the host to which we want to connect */
4080     /* 'svcbuf'   contains the service name                                 */
4081     /* 'service->s_port' contains the port number in network byte order     */
4082
4083     /* If we are using an http proxy, we need to create a buffer containing */
4084     /*   hostname:port-number                                               */
4085     /* to pass to the http_connect() function.  Then we need to replace     */
4086     /* 'namecopy' with the name of the proxy server and the service->s_port */
4087     /* with the port number of the proxy (default port 80).                 */
4088
4089     if ( tcp_http_proxy ) {
4090         ckmakmsg(proxycopy,sizeof(proxycopy),namecopy,":",
4091                  ckuitoa(ntohs(service->s_port)),NULL);
4092         ckstrncpy(namecopy,tcp_http_proxy,NAMECPYL);
4093
4094         p = namecopy;                       /* Was a service requested? */
4095         while (*p != '\0' && *p != ':') p++; /* Look for colon */
4096         if (*p == ':') {                    /* Have a colon */
4097             debug(F110,"netopen name has colon",namecopy,0);
4098             *p++ = '\0';                    /* Get service name or number */
4099         } else {
4100             strcpy(++p,"http");
4101         }
4102
4103         service = ckgetservice(namecopy,p,namecopy,NAMECPYL);
4104         if (!service) {
4105             fprintf(stderr, "Can't find port for service %s\n", p);
4106 #ifdef TGVORWIN
4107             debug(F101,"netopen can't get service for proxy","",socket_errno);
4108 #else
4109             debug(F101,"netopen can't get service for proxy","",errno);
4110 #endif /* TGVORWIN */
4111             errno = 0;                  /* (rather than mislead) */
4112             return(-1);
4113         }
4114         ckstrncpy(p,ckuitoa(ntohs(service->s_port)),NAMECPYL-(p-namecopy));
4115
4116     }
4117 #endif /* NOHTTP */
4118
4119     /* Set up socket structure and get host address */
4120
4121     bzero((char *)&r_addr, sizeof(r_addr));
4122     debug(F100,"netopen bzero ok","",0);
4123 /*
4124    NOTE: Originally the inet_addr() check was #ifdef NT, but is enabled for
4125    all as of 20 Sep 97, to allow people to "set host" to a specific numeric IP
4126    address without going through the multihomed host sequence and winding up
4127    at a different place than the one requested.
4128 */
4129 #ifdef INADDR_NONE
4130     debug(F101,"netopen INADDR_NONE defined","",INADDR_NONE);
4131 #else /* INADDR_NONE */
4132     debug(F100,"netopen INADDR_NONE not defined","",0);
4133 #endif /* INADDR_NONE */
4134 #ifdef INADDRX
4135     debug(F100,"netopen INADDRX defined","",0);
4136 #else /* INADDRX */
4137     debug(F100,"netopen INADDRX not defined","",0);
4138 #endif /* INADDRX */
4139
4140 #ifndef NOMHHOST
4141 #ifdef INADDRX
4142     iax = inet_addr(namecopy);
4143     debug(F111,"netopen inet_addr",namecopy,iax.s_addr);
4144 #else /* INADDRX */
4145 #ifdef INADDR_NONE
4146     iax.s_addr = inet_addr(namecopy);
4147     debug(F111,"netopen inet_addr",namecopy,iax.s_addr);
4148 #else /* INADDR_NONE */
4149 #ifdef SOLARIS
4150     /* In Solaris inet_addr() is of type in_addr_t which is uint32_t */
4151     /* (unsigned) yet it returns -1 (signed) on failure. */
4152     /* It makes a difference in 64-bit builds. */
4153     rc_inet_addr = inet_addr(namecopy); /* Assign return code to an int */
4154     iax = (unsigned) rc_inet_addr;      /* and from there to whatever.. */
4155 #else
4156 #ifndef datageneral
4157     iax = (unsigned int) inet_addr(namecopy);
4158 #else
4159     iax = -1L;
4160 #endif /* datageneral */
4161 #endif /* SOLARIS */
4162     debug(F111,"netopen rc_inet_addr",namecopy,rc_inet_addr);
4163     debug(F111,"netopen inet_addr",namecopy,iax);
4164 #endif /* INADDR_NONE */
4165 #endif /* INADDRX */
4166
4167     dns = 0;
4168     if (
4169 /* This might give warnings on 64-bit platforms but they should be harmless */
4170 /* because INADDR_NONE should be all 1's anyway, thus the OR part is */
4171 /* probably superfluous -- not sure why it's even there, maybe it should be */
4172 /* removed. */
4173 #ifdef SOLARIS
4174         rc_inet_addr == -1
4175 #else
4176 #ifdef INADDR_NONE
4177         iax.s_addr == INADDR_NONE /* || iax.s_addr == (unsigned long) -1L */
4178 #else /* INADDR_NONE */
4179         iax < 0
4180 #endif /* INADDR_NONE */
4181 #endif /* SOLARIS */
4182         ) {
4183         if (!quiet) {
4184             printf(" DNS Lookup... ");
4185             fflush(stdout);
4186         }
4187         if ((host = gethostbyname(namecopy)) != NULL) {
4188             debug(F110,"netopen gethostbyname != NULL",namecopy,0);
4189             host = ck_copyhostent(host);
4190             dns = 1;                    /* Remember we performed dns lookup */
4191             r_addr.sin_family = host->h_addrtype;
4192             if (tcp_rdns && host->h_name && host->h_name[0]
4193 #ifndef NOHTTP
4194                  && (tcp_http_proxy == NULL)
4195 #endif /* NOHTTP */
4196                 ) {
4197 #ifdef COMMENT
4198                 ckstrncpy(xxname,host->h_name,XXNAMELEN);
4199                 debug(F110,"netopen xxname[1]",xxname,0);
4200                 if ((XXNAMELEN - (int)strlen(name)) > ((int)strlen(svcbuf)+1)){
4201                     ckstrncat(xxname,":",XXNAMELEN - (int)strlen(xxname));
4202                     ckstrncat(xxname,svcbuf,XXNAMELEN - (int)strlen(xxname));
4203                     debug(F110,"netopen xxname[2]",xxname,0);
4204                 }
4205                 name = (char *)xxname;
4206 #else
4207                 ckstrncpy(name,host->h_name,80);  /* Bad Bad Bad */
4208                 if ( (80-strlen(name)) > (strlen(svcbuf)+1) ) {
4209                     ckstrncat(name,":",80-strlen(name));
4210                     ckstrncat(name,svcbuf,80-strlen(name));
4211                 }
4212 #endif  /* COMMENT */
4213             }
4214             debug(F110,"netopen name after lookup",name,0);
4215
4216 #ifdef HADDRLIST
4217 #ifdef h_addr
4218             /* This is for trying multiple IP addresses - see <netdb.h> */
4219             if (!(host->h_addr_list))
4220               return(-1);
4221             bcopy(host->h_addr_list[0],
4222                   (caddr_t)&r_addr.sin_addr,
4223                   host->h_length
4224                   );
4225 #else
4226             bcopy(host->h_addr, (caddr_t)&r_addr.sin_addr, host->h_length);
4227 #endif /* h_addr */
4228 #else  /* HADDRLIST */
4229 #ifdef HPUX6
4230             r_addr.sin_addr.s_addr = (u_long)host->h_addr;
4231 #else  /* HPUX6 */
4232             bcopy(host->h_addr, (caddr_t)&r_addr.sin_addr, host->h_length);
4233 #endif  /* HPUX6 */
4234 #endif /* HADDRLIST */
4235
4236 #ifndef HPUX6
4237             debug(F111,"BCOPY","host->h_length",host->h_length);
4238 #endif  /* HPUX6 */
4239         }
4240     }
4241 #endif /* NOMHHOST */
4242
4243     debug(F101,"netopen dns","",dns);
4244
4245     if (!dns) {
4246 #ifdef INADDRX
4247 /* inet_addr() is of type struct in_addr */
4248         struct in_addr ina;
4249         unsigned long uu;
4250         debug(F100,"netopen gethostbyname == NULL: INADDRX","",0);
4251         ina = inet_addr(namecopy);
4252         uu = *(unsigned int *)&ina;
4253 #else /* Not INADDRX */
4254 /* inet_addr() is unsigned long */
4255         unsigned long uu;
4256         debug(F100,"netopen gethostbyname == NULL: Not INADDRX","",0);
4257         uu = inet_addr(namecopy);
4258 #endif /* INADDRX */
4259         debug(F101,"netopen uu","",uu);
4260         if (
4261 #ifdef INADDR_NONE
4262             !(uu == INADDR_NONE || uu == (unsigned int) -1L)
4263 #else   /* INADDR_NONE */
4264             uu != ((unsigned long)-1)
4265 #endif /* INADDR_NONE */
4266             ) {
4267             r_addr.sin_addr.s_addr = uu;
4268             r_addr.sin_family = AF_INET;
4269         } else {
4270 #ifdef VMS
4271             fprintf(stdout, "\r\n");    /* complete any previous message */
4272 #endif /* VMS */
4273             fprintf(stderr, "Can't get address for %s\n", namecopy);
4274 #ifdef TGVORWIN
4275             debug(F101,"netopen can't get address","",socket_errno);
4276 #else
4277             debug(F101,"netopen can't get address","",errno);
4278 #endif /* TGVORWIN */
4279             errno = 0;                  /* Rather than mislead */
4280             return(-1);
4281         }
4282     }
4283
4284     /* Get a file descriptor for the connection. */
4285
4286     r_addr.sin_port = service->s_port;
4287     ckstrncpy(ipaddr,(char *)inet_ntoa(r_addr.sin_addr),20);
4288     debug(F110,"netopen trying",ipaddr,0);
4289     if (!quiet && *ipaddr) {
4290         printf(" Trying %s... ", ipaddr);
4291         fflush(stdout);
4292     }
4293
4294     /* Loop to try additional IP addresses, if any. */
4295
4296     do {
4297 #ifdef EXCELAN
4298         send_socket.sin_family = AF_INET;
4299         send_socket.sin_addr.s_addr = 0;
4300         send_socket.sin_port = 0;
4301         if ((ttyfd = socket(SOCK_STREAM, (struct sockproto *)0,
4302                             &send_socket, SO_REUSEADDR)) < 0)
4303 #else  /* EXCELAN */
4304 #ifdef NT
4305 #ifdef COMMENT_X
4306        /*
4307          Must make sure that all sockets are opened in
4308          Non-overlapped mode since we use the standard
4309          C RTL functions to read and write data.
4310          But it doesn't seem to work as planned.
4311        */
4312           {
4313               int optionValue = SO_SYNCHRONOUS_NONALERT;
4314               if (setsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE,
4315                              (char *) &optionValue, sizeof(optionValue))
4316                   != NO_ERROR)
4317                 return(-1);
4318           }
4319 #endif /* COMMENT */
4320 #endif /* NT */
4321
4322         if ((ttyfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
4323 #endif /* EXCELAN */
4324             {
4325 #ifdef EXCELAN
4326                 experror("TCP socket error");
4327 #else
4328 #ifdef VMS
4329                 fprintf(stdout, "\r\n"); /* complete any previous stdout */
4330 #endif /* VMS */
4331 #ifdef TGVORWIN
4332 #ifdef OLD_TWG
4333                 errno = socket_errno;
4334 #endif /* OLD_TWG */
4335                 socket_perror("TCP socket error");
4336                 debug(F101,"netopen socket error","",socket_errno);
4337 #else
4338                 perror("TCP socket error");
4339                 debug(F101,"netopen socket error","",errno);
4340 #endif /* TGVORWIN */
4341 #endif /* EXCELAN */
4342                 return (-1);
4343             }
4344         errno = 0;
4345
4346 #ifdef RLOGCODE
4347        /* Not part of the RLOGIN RFC, but the BSD implementation     */
4348        /* requires that the client port be a priviliged port (<1024) */
4349        /* on a Unix system this would require SuperUser permissions  */
4350        /* thereby saying that the root of the Unix system has given  */
4351        /* permission for this connection to be created               */
4352        if (service->s_port == htons((unsigned short)RLOGIN_PORT)) {
4353            static unsigned short lport = 1024;  /* max reserved port */
4354 #ifdef OS2
4355            int s_errno;
4356 #endif /* OS2 */
4357
4358            lport--;                     /* Make sure we do not reuse a port */
4359            if (lport == 512)
4360              lport = 1023;
4361
4362            sin.sin_family = AF_INET;
4363            if (tcp_address) {
4364 #ifdef INADDRX
4365                inaddrx = inet_addr(tcp_address);
4366                sin.sin_addr.s_addr = *(unsigned long *)&inaddrx;
4367 #else
4368                sin.sin_addr.s_addr = inet_addr(tcp_address);
4369 #endif /* INADDRX */
4370            } else
4371              sin.sin_addr.s_addr = INADDR_ANY;
4372            while (1) {
4373                sin.sin_port = htons(lport);
4374                if (bind(ttyfd, (struct sockaddr *)&sin, sizeof(sin)) >= 0)
4375                  break;
4376 #ifdef OS2
4377                s_errno = socket_errno;
4378                if (s_errno && /* OS2 bind fails with 0, if already in use */
4379 #ifdef NT
4380                    s_errno != WSAEADDRINUSE
4381 #else
4382                    s_errno != SOCEADDRINUSE &&
4383                    s_errno != (SOCEADDRINUSE - SOCBASEERR)
4384 #endif /* NT */
4385                    )
4386 #else /* OS2 */
4387 #ifdef TGVORWIN
4388                  if (socket_errno != EADDRINUSE)
4389 #else
4390                  if (errno != EADDRINUSE)
4391 #endif /* TGVORWIN */
4392 #endif /* OS2 */
4393                    {
4394 #ifdef COMMENT
4395                        printf("\nBind failed with errno %d  for port %d.\n",
4396 #ifdef OS2
4397                               s_errno
4398 #else
4399 #ifdef TGVORWIN
4400                               socket_errno
4401 #else
4402                               errno
4403 #endif /* TGVORWIN */
4404 #endif /* OS2 */
4405                               , lport
4406                               );
4407 #ifdef OS2
4408                        debug(F101,"rlogin bind failed","",s_errno);
4409 #else
4410 #ifdef TGVORWIN
4411                        debug(F101,"rlogin bind failed","",socket_errno);
4412 #ifdef OLD_TWG
4413                        errno = socket_errno;
4414 #endif /* OLD_TWG */
4415                        socket_perror("rlogin bind");
4416 #else
4417                        debug(F101,"rlogin bind failed","",errno);
4418                        perror("rlogin bind");
4419 #endif /* TGVORWIN */
4420 #endif /* OS2 */
4421 #else  /* COMMENT */
4422 #ifdef OS2
4423                        debug(F101,"rlogin bind s_errno","",s_errno);
4424                        perror("rlogin bind");
4425 #else
4426 #ifdef VMS
4427                        printf("\r\n");  /* complete any previous message */
4428 #endif /* VMS */
4429 #ifdef TGVORWIN
4430                        debug(F101,"rlogin bind socket_errno","",socket_errno);
4431 #ifdef OLD_TWG
4432                        errno = socket_errno;
4433 #endif /* OLD_TWG */
4434                        socket_perror("rlogin bind");
4435 #else
4436                        debug(F101,"rlogin bind errno","",errno);
4437                        perror("rlogin bind");
4438 #endif /* TGVORWIN */
4439 #endif /* OS2 */
4440                        debug(F101,"rlogin local port","",lport);
4441 #endif /* COMMENT */
4442                        netclos();
4443                        return -1;
4444                    }
4445                lport--;
4446                if (lport == 512 /* lowest reserved port to use */ ) {
4447                    printf("\nNo reserved ports available.\n");
4448                    netclos();
4449                    return -1;
4450                }
4451            }
4452            debug(F101,"rlogin lport","",lport);
4453            ttnproto = NP_RLOGIN;
4454        } else
4455 #endif /* RLOGCODE  */
4456
4457        /* If a specific TCP address on the local host is desired we */
4458        /* must bind it to the socket.                               */
4459 #ifndef datageneral
4460          if (tcp_address) {
4461              int s_errno;
4462
4463              debug(F110,"netopen binding socket to",tcp_address,0);
4464              bzero((char *)&sin,sizeof(sin));
4465              sin.sin_family = AF_INET;
4466 #ifdef INADDRX
4467              inaddrx = inet_addr(tcp_address);
4468              sin.sin_addr.s_addr = *(unsigned long *)&inaddrx;
4469 #else
4470              sin.sin_addr.s_addr = inet_addr(tcp_address);
4471 #endif /* INADDRX */
4472              sin.sin_port = 0;
4473              if (bind(ttyfd, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
4474                  s_errno = socket_errno; /* Save error code */
4475 #ifdef TCPIPLIB
4476                  socket_close(ttyfd);
4477 #else /* TCPIPLIB */
4478                  close(ttyfd);
4479 #endif /* TCPIPLIB */
4480                  ttyfd = -1;
4481                  wasclosed = 1;
4482                  errno = s_errno;       /* and report this error */
4483                  debug(F101,"netopen bind errno","",errno);
4484                  return(-1);
4485              }
4486          }
4487 #endif /* datageneral */
4488
4489 /* Now connect to the socket on the other end. */
4490
4491 #ifdef EXCELAN
4492         if (connect(ttyfd, &r_addr) < 0)
4493 #else
4494 #ifdef NT
4495           WSASafeToCancel = 1;
4496 #endif /* NT */
4497         if (connect(ttyfd, (struct sockaddr *)&r_addr, sizeof(r_addr)) < 0)
4498 #endif /* EXCELAN */
4499           {
4500 #ifdef NT
4501               WSASafeToCancel = 0;
4502 #endif /* NT */
4503 #ifdef OS2
4504               i = socket_errno;
4505 #else /* OS2 */
4506 #ifdef TGVORWIN
4507               i = socket_errno;
4508 #else
4509               i = errno;                /* Save error code */
4510 #endif /* TGVORWIN */
4511 #endif /* OS2 */
4512 #ifdef RLOGCODE
4513               if (
4514 #ifdef OS2
4515                  i && /* OS2 bind fails with 0, if already in use */
4516 #ifdef NT
4517                  i == WSAEADDRINUSE
4518 #else
4519                  (i == SOCEADDRINUSE ||
4520                  i == (SOCEADDRINUSE - SOCBASEERR))
4521 #endif /* NT */
4522 #else /* OS2 */
4523 #ifdef TGVORWIN
4524                   socket_errno == EADDRINUSE
4525 #else
4526                   errno == EADDRINUSE
4527 #endif /* TGVORWIN */
4528 #endif /* OS2 */
4529                   && ttnproto == NP_RLOGIN) {
4530 #ifdef TCPIPLIB
4531                    socket_close(ttyfd); /* Close it. */
4532 #else
4533                    close(ttyfd);
4534 #endif /* TCPIPLIB */
4535                    continue;            /* Try a different lport */
4536                }
4537 #endif /* RLOGCODE */
4538 #ifdef HADDRLIST
4539 #ifdef h_addr
4540               if (host && host->h_addr_list && host->h_addr_list[1]) {
4541                   perror("");
4542                   host->h_addr_list++;
4543                   bcopy(host->h_addr_list[0],
4544                         (caddr_t)&r_addr.sin_addr,
4545                         host->h_length);
4546
4547                   ckstrncpy(ipaddr,(char *)inet_ntoa(r_addr.sin_addr),20);
4548                   debug(F110,"netopen h_addr_list",ipaddr,0);
4549                   if (!quiet && *ipaddr) {
4550                       printf(" Trying %s... ", ipaddr);
4551                       fflush(stdout);
4552                   }
4553 #ifdef TCPIPLIB
4554                   socket_close(ttyfd); /* Close it. */
4555 #else
4556                   close(ttyfd);
4557 #endif /* TCPIPLIB */
4558                   continue;
4559               }
4560 #endif /* h_addr */
4561 #endif  /* HADDRLIST */
4562               netclos();
4563               ttyfd = -1;
4564               wasclosed = 1;
4565               ttnproto = NP_NONE;
4566               errno = i;                /* And report this error */
4567 #ifdef EXCELAN
4568               if (errno) experror("netopen connect");
4569 #else
4570 #ifdef TGVORWIN
4571               debug(F101,"netopen connect error","",socket_errno);
4572               /* if (errno) socket_perror("netopen connect"); */
4573 #ifdef OLD_TWG
4574               errno = socket_errno;
4575 #endif /* OLD_TWG */
4576               if (!quiet)
4577                 socket_perror("netopen connect");
4578 #else /* TGVORWIN */
4579               debug(F101,"netopen connect errno","",errno);
4580 #ifdef VMS
4581               if (!quiet)
4582                 perror("\r\nFailed");
4583 #else
4584               if (!quiet)
4585                 perror("Failed");
4586 #endif /* VMS */
4587 #ifdef DEC_TCPIP
4588               if (!quiet)
4589                 perror("netopen connect");
4590 #endif /* DEC_TCPIP */
4591 #ifdef CMU_TCPIP
4592               if (!quiet)
4593                 perror("netopen connect");
4594 #endif /* CMU_TCPIP */
4595 #endif /* TGVORWIN */
4596 #endif /* EXCELAN */
4597               return(-1);
4598           }
4599 #ifdef NT
4600         WSASafeToCancel = 0;
4601 #endif /* NT */
4602         isconnect = 1;
4603     } while (!isconnect);
4604
4605 #ifdef NON_BLOCK_IO
4606     on = 1;
4607     x = socket_ioctl(ttyfd,FIONBIO,&on);
4608     debug(F101,"netopen FIONBIO","",x);
4609 #endif /* NON_BLOCK_IO */
4610
4611 #ifdef NT_TCP_OVERLAPPED
4612     OverlappedWriteInit();
4613     OverlappedReadInit();
4614 #endif /* NT_TCP_OVERLAPPED */
4615
4616     ttnet = nett;                       /* TCP/IP (sockets) network */
4617
4618 #ifndef NOHTTP
4619     /* We have succeeded in connecting to the HTTP PROXY.  So now we   */
4620     /* need to attempt to connect through the proxy to the actual host */
4621     /* If that is successful, we have to pretend that we made a direct */
4622     /* connection to the actual host.                                  */
4623
4624     if ( tcp_http_proxy ) {
4625 #ifdef OS2
4626         char * agent = "Kermit 95";             /* Default user agent */
4627 #else
4628         char * agent = "C-Kermit";
4629 #endif /* OS2 */
4630
4631         if (http_connect(ttyfd,
4632                          tcp_http_proxy_agent ? tcp_http_proxy_agent : agent,
4633                          NULL,
4634                          tcp_http_proxy_user,
4635                          tcp_http_proxy_pwd,
4636                          0,
4637                          proxycopy
4638                          ) < 0) {
4639             netclos();
4640             return(-1);
4641         }
4642
4643         ckstrncpy(namecopy,proxycopy,NAMECPYL);
4644         p = namecopy;                       /* Was a service requested? */
4645         while (*p != '\0' && *p != ':') p++; /* Look for colon */
4646         *p = '\0';
4647     }
4648 #endif /* NOHTTP */
4649
4650     /* Jeff - Does this next block of code that set's the protocol */
4651     /* need to be here anymore?  5/10/2000                         */
4652
4653     /* There are certain magic port numbers that when used require */
4654     /* the use of specific protocols.  Check this now before we    */
4655     /* set the SO_OOBINLINE state or we might get it wrong.        */
4656     x = ntohs((unsigned short)service->s_port);
4657     svcnum = x;
4658     /* See if the service is TELNET. */
4659     if (x == TELNET_PORT) {
4660         /* Yes, so if raw port not requested */
4661 #ifdef COMMENT
4662         /* Jeff 2005/12/30 */
4663         if (ttnproto != NP_TCPRAW && ttnproto != NP_SSL_RAW && 
4664             ttnproto != NP_TLS_RAW && ttnproto != NP_NONE)
4665 #else
4666         /* fdc 2005/12/04 */
4667         if (ttnproto != NP_TCPRAW && ttnproto != NP_NONE)
4668 #endif  /* COMMENT */
4669           ttnproto = NP_TELNET;         /* Select TELNET protocol. */
4670     }
4671 #ifdef RLOGCODE
4672     else if (x == RLOGIN_PORT) {
4673         ttnproto = NP_RLOGIN;
4674     }
4675 #ifdef CK_KERBEROS
4676     /* There is no good way to do this.  If the user didn't tell    */
4677     /* which one to use up front.  We may guess wrong if the user   */
4678     /* has both Kerberos versions installed and valid TGTs for each */
4679     else if (x == KLOGIN_PORT &&
4680              ttnproto != NP_K4LOGIN &&
4681              ttnproto != NP_K5LOGIN) {
4682         if (ck_krb5_is_installed() &&
4683             ck_krb5_is_tgt_valid())
4684           ttnproto = NP_K5LOGIN;
4685         else if (ck_krb4_is_installed() && ck_krb4_is_tgt_valid())
4686           ttnproto = NP_K4LOGIN;
4687         else
4688           ttnproto = NP_K4LOGIN;
4689     } else if (x == EKLOGIN_PORT &&
4690                ttnproto != NP_EK4LOGIN &&
4691                ttnproto != NP_EK5LOGIN) {
4692         if (ck_krb5_is_installed() && ck_krb5_is_tgt_valid())
4693           ttnproto = NP_EK5LOGIN;
4694         else if (ck_krb4_is_installed() && ck_krb4_is_tgt_valid())
4695           ttnproto = NP_EK4LOGIN;
4696         else
4697           ttnproto = NP_EK4LOGIN;
4698     }
4699 #endif /* CK_KERBEROS */
4700 #endif /* RLOGCODE */
4701 #ifdef IKS_OPTION
4702     else if (x == KERMIT_PORT) {        /* IKS uses Telnet protocol */
4703         if (ttnproto == NP_NONE)
4704           ttnproto = NP_KERMIT;
4705     }
4706 #endif /* IKS_OPTION */
4707
4708 #ifdef SO_OOBINLINE
4709 /*
4710   The symbol SO_OOBINLINE is not known to Ultrix 2.0.
4711   It means "leave out of band data inline".  The normal value is 0x0100,
4712   but don't try this on systems where the symbol is undefined.
4713 */
4714 /*
4715   Note from Jeff Altman: 12/13/95
4716   In implementing rlogin protocol I have come to the conclusion that it is
4717   a really bad idea to read out-of-band data inline.
4718   At least Windows and OS/2 does not handle this well.
4719   And if you need to know that data is out-of-band, then it becomes
4720   absolutely pointless.
4721
4722   Therefore, at least on OS2 and Windows (NT) I have changed the value of
4723   on to 0, so that out-of-band data stays out-of-band.
4724
4725   12/18/95
4726   Actually, OOB data should be read inline when possible.  Especially with
4727   protocols that don't care about the Urgent flag.  This is true with Telnet.
4728   With Rlogin, you need to be able to catch OOB data.  However, the best
4729   way to do this is to set a signal handler on SIGURG.  This isn't possible
4730   on OS/2 and Windows.  But it is in UNIX.  We will also need OOB data for
4731   FTP so better create a general mechanism.
4732
4733   The reason for making OOB data be inline is that the standard ttinc/ttoc
4734   calls can be used for reading that data on UNIX systems.  If we didn't
4735   have the OOBINLINE option set then we would have to use recv(,MSG_OOB)
4736   to read it.
4737 */
4738 #ifdef RLOGCODE
4739 #ifdef TCPIPLIB
4740     if (ttnproto == NP_RLOGIN
4741 #ifdef CK_KERBEROS
4742         || ttnproto == NP_K4LOGIN || ttnproto == NP_EK4LOGIN
4743         || ttnproto == NP_K5LOGIN || ttnproto == NP_EK5LOGIN
4744 #endif /* CK_KERBEROS */
4745       )
4746       on = 0;
4747 #else /* TCPIPLIB */
4748     if (ttnproto == NP_RLOGIN
4749 #ifdef CK_KERBEROS
4750          || ttnproto == NP_K4LOGIN || ttnproto == NP_EK4LOGIN
4751          || ttnproto == NP_K5LOGIN || ttnproto == NP_EK5LOGIN
4752 #endif /* CK_KERBEROS */
4753          ) {
4754         debug(F100,"Installing rlogoobh on SIGURG","",0);
4755         signal(SIGURG, rlogoobh);
4756         on = 0;
4757     } else {
4758         debug(F100,"Ignoring SIGURG","",0);
4759         signal(SIGURG, SIG_DFL);
4760     }
4761 #endif /* TCPIPLIB */
4762 #endif /* RLOGCODE */
4763
4764 #ifdef datageneral
4765     setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
4766 #else
4767 #ifdef BSD43
4768     setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
4769 #else
4770 #ifdef OSF1
4771     setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
4772 #else
4773 #ifdef POSIX
4774     setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
4775 #else
4776 #ifdef MOTSV88R4
4777     setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
4778 #else
4779 #ifdef SOLARIS
4780 /*
4781   Maybe this applies to all SVR4 versions, but the other (else) way has been
4782   compiling and working fine on all the others, so best not to change it.
4783 */
4784     setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
4785 #else
4786 #ifdef OSK
4787     setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
4788 #else
4789 #ifdef OS2
4790     {
4791         int rc;
4792         rc = setsockopt(ttyfd,
4793                         SOL_SOCKET,
4794                         SO_OOBINLINE,
4795                         (char *) &on,
4796                         sizeof on
4797                         );
4798         debug(F111,"setsockopt SO_OOBINLINE",on ? "on" : "off" ,rc);
4799     }
4800 #else
4801 #ifdef VMS /* or, at least, VMS with gcc */
4802     setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
4803 #else
4804 #ifdef CLIX
4805     setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
4806 #else
4807     setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE, &on, sizeof on);
4808 #endif /* CLIX */
4809 #endif /* VMS */
4810 #endif /* OS2 */
4811 #endif /* OSK */
4812 #endif /* SOLARIS */
4813 #endif /* MOTSV88R4 */
4814 #endif /* POSIX */
4815 #endif /* BSD43 */
4816 #endif /* OSF1 */
4817 #endif /* datageneral */
4818 #endif /* SO_OOBINLINE */
4819
4820 #ifndef NOTCPOPTS
4821 #ifndef datageneral
4822 #ifdef SOL_SOCKET
4823 #ifdef TCP_NODELAY
4824     no_delay(ttyfd,tcp_nodelay);
4825 #endif /* TCP_NODELAY */
4826 #ifdef SO_KEEPALIVE
4827     keepalive(ttyfd,tcp_keepalive);
4828 #endif /* SO_KEEPALIVE */
4829 #ifdef SO_LINGER
4830     ck_linger(ttyfd,tcp_linger, tcp_linger_tmo);
4831 #endif /* SO_LINGER */
4832 #ifdef SO_SNDBUF
4833     sendbuf(ttyfd,tcp_sendbuf);
4834 #endif /* SO_SNDBUF */
4835 #ifdef SO_RCVBUF
4836     recvbuf(ttyfd,tcp_recvbuf);
4837 #endif /* SO_RCVBUF */
4838 #endif /* SOL_SOCKET */
4839 #endif /* datageneral */
4840 #endif /* NOTCPOPTS */
4841
4842 #ifndef datageneral
4843     /* Find out our own IP address. */
4844     /* We need the l_addr structure for [E]KLOGIN. */
4845     l_slen = sizeof(l_addr);
4846     bzero((char *)&l_addr, l_slen);
4847 #ifndef EXCELAN
4848     if (!getsockname(ttyfd, (struct sockaddr *)&l_addr, &l_slen)) {
4849         char * s = (char *)inet_ntoa(l_addr.sin_addr);
4850         ckstrncpy(myipaddr, s, 20);
4851         debug(F110,"getsockname",myipaddr,0);
4852     }
4853 #endif /* EXCELAN */
4854 #endif /* datageneral */
4855
4856 /*
4857   This is really only needed for Kerberos IV but is useful information in any
4858   case.  If we connect to a name that is really a pool, we need to get the
4859   name of the machine we are actually connecting to for K4 to authenticate
4860   properly.  This way we also update the names properly.
4861
4862   However, it is a security hole when used with insecure DNS.
4863
4864   Note: This does not work on Windows 95 or Windows NT 3.5x.  This is because
4865   of the Microsoft implementation of gethostbyaddr() in both Winsock 1.1
4866   and Winsock 2.0 on those platforms.  Their algorithm is:
4867
4868   1. Check the HOSTENT cache.
4869   2. Check the HOSTS file at %SystemRoot%\System32\DRIVERS\ETC.
4870   3. Do a DNS query if the DNS server is configured for name resolution.
4871   4. Do an additional NetBIOS remote adapter status to an IP address for its
4872      NetBIOS name table. This step is specific only to the Windows NT version
4873      3.51 implementation.
4874
4875   The problem is the use of the HOSTENT cache.  It means that gethostbyaddr()
4876   can not be used to resolve the real name of machine if it was originally
4877   accessed by an alias used to represent a cluster.
4878 */
4879      if ((tcp_rdns && dns || tcp_rdns == SET_ON
4880 #ifdef CK_KERBEROS
4881          || tcp_rdns == SET_AUTO &&
4882           (ck_krb5_is_installed() || ck_krb4_is_installed())
4883 #endif /* CK_KERBEROS */
4884          )
4885 #ifndef NOHTTP
4886           && (tcp_http_proxy == NULL)
4887 #endif /* NOHTTP */
4888 #ifdef CK_SSL
4889           && !(ssl_only_flag || tls_only_flag)
4890 #endif /* CK_SSL */
4891          ) {
4892 #ifdef NT
4893         if (isWin95())
4894           sleep(1);
4895 #endif /* NT */
4896         if (!quiet) {
4897             printf(" Reverse DNS Lookup... ");
4898             fflush(stdout);
4899         }
4900         if (host = gethostbyaddr((char *)&r_addr.sin_addr,4,PF_INET)) {
4901             char * s;
4902             host = ck_copyhostent(host);
4903             debug(F100,"netopen gethostbyname != NULL","",0);
4904             if (!quiet) {
4905                 printf("(OK)\n");
4906                 fflush(stdout);
4907             }
4908             s = host->h_name;
4909             if (!s) {                   /* This can happen... */
4910                 debug(F100,"netopen host->h_name is NULL","",0);
4911                 s = "";
4912             }
4913             /* Something is wrong with inet_ntoa() on HPUX 10.xx */
4914             /* The compiler says "Integral value implicitly converted to */
4915             /* pointer in assignment."  The prototype is right there */
4916             /* in <arpa/inet.h> so what's the problem? */
4917             /* Ditto in HP-UX 5.x, but not 8.x or 9.x... */
4918             if (!*s) {                  /* No name so substitute the address */
4919                 debug(F100,"netopen host->h_name is empty","",0);
4920                 s = inet_ntoa(r_addr.sin_addr); /* Convert address to string */
4921                 if (!s)                 /* Trust No 1 */
4922                   s = "";
4923                 if (*s) {               /* If it worked, use this string */
4924                     ckstrncpy(ipaddr,s,20);
4925                 }
4926                 s = ipaddr;             /* Otherwise stick with the IP */
4927                 if (!*s)                /* or failing that */
4928                   s = namecopy;         /* the name we were called with. */
4929             }
4930             if (*s) {                   /* Copying into our argument? */
4931                 ckstrncpy(name,s,80);   /* Bad Bad Bad */
4932                 if ( (80-strlen(name)) > (strlen(svcbuf)+1) ) {
4933                     ckstrncat(name,":",80-strlen(name));
4934                     ckstrncat(name,svcbuf,80-strlen(name));
4935                 }
4936             }
4937             if (!quiet && *s
4938 #ifndef NOICP
4939                 && !doconx
4940 #endif /* NOICP */
4941                 ) {
4942                 printf(" %s connected on port %s\n",s,p);
4943 #ifdef BETADEBUG
4944                 /* This is simply for testing the DNS entries */
4945                 if (host->h_aliases) {
4946                     char ** a = host->h_aliases;
4947                     while (*a) {
4948                         printf(" alias => %s\n",*a);
4949                         a++;
4950                     }
4951                 }
4952 #endif /* BETADEBUG */
4953             }
4954         } else {
4955             if (!quiet) printf("Failed.\n");
4956         }
4957     } else if (!quiet) printf("(OK)\n");
4958     if (!quiet) fflush(stdout);
4959
4960     /* This should already have been done but just in case */
4961     ckstrncpy(ipaddr,(char *)inet_ntoa(r_addr.sin_addr),20);
4962
4963 #ifdef CK_SECURITY
4964
4965     /* Before Initialization Telnet/Rlogin Negotiations Init Kerberos */
4966 #ifndef NOHTTP
4967     if (tcp_http_proxy) {
4968         for (i=strlen(proxycopy); i >= 0 ; i--)
4969             if ( proxycopy[i] == ':' )
4970                 proxycopy[i] = '\0';
4971     }
4972 #endif /* NOHTTP */
4973     ck_auth_init(
4974 #ifndef NOHTTP
4975                  tcp_http_proxy ? proxycopy :
4976 #endif /* NOHTTP */
4977                  (tcp_rdns && host && host->h_name && host->h_name[0]) ?
4978                  (char *)host->h_name : (namecopy2[0] ? namecopy2 : 
4979                                         (namecopy[0] ? namecopy : ipaddr)),
4980                  ipaddr,
4981                  uidbuf,
4982                  ttyfd
4983                  );
4984 #endif /* CK_SECURITY */
4985 #ifdef CK_SSL
4986     if (ck_ssleay_is_installed()) {
4987         if (!ssl_tn_init(SSL_CLIENT)) {
4988             debug(F100,"netopen ssl_tn_init() failed","",0);
4989             if (bio_err!=NULL) {
4990                 BIO_printf(bio_err,"ssl_tn_init() failed\n");
4991                 ERR_print_errors(bio_err);
4992             } else {
4993                 fflush(stderr);
4994                 fprintf(stderr,"ssl_tn_init() failed\n");
4995                 ERR_print_errors_fp(stderr);
4996             }
4997             if (tls_only_flag || ssl_only_flag) {
4998                 debug(F100,"netopen ssl/tls required","",0);
4999                 netclos();
5000                 return(-1);
5001             }
5002
5003             /* we will continue to accept the connection   */
5004             /* without SSL or TLS support unless required. */
5005             if ( TELOPT_DEF_S_ME_MODE(TELOPT_START_TLS) != TN_NG_MU )
5006                 TELOPT_DEF_S_ME_MODE(TELOPT_START_TLS) = TN_NG_RF;
5007             if ( TELOPT_DEF_S_U_MODE(TELOPT_START_TLS) != TN_NG_MU )
5008                 TELOPT_DEF_S_U_MODE(TELOPT_START_TLS) = TN_NG_RF;
5009             if ( TELOPT_DEF_C_ME_MODE(TELOPT_START_TLS) != TN_NG_MU )
5010                 TELOPT_DEF_C_ME_MODE(TELOPT_START_TLS) = TN_NG_RF;
5011             if ( TELOPT_DEF_C_U_MODE(TELOPT_START_TLS) != TN_NG_MU )
5012                 TELOPT_DEF_C_U_MODE(TELOPT_START_TLS) = TN_NG_RF;
5013         } else if ( ck_ssl_outgoing(ttyfd) < 0 ) {
5014             debug(F100,"ck_ssl_outgoing() failed","",0);
5015             netclos();
5016             return(-1);
5017         }
5018     }
5019 #endif /* CK_SSL */
5020
5021 #ifdef RLOGCODE
5022     if (ttnproto == NP_RLOGIN
5023 #ifdef CK_KERBEROS
5024         || ttnproto == NP_K4LOGIN || ttnproto == NP_EK4LOGIN
5025         || ttnproto == NP_K5LOGIN || ttnproto == NP_EK5LOGIN
5026 #endif /* CK_KERBEROS */
5027         ) {                             /* Similar deal for rlogin */
5028         if (rlog_ini(((tcp_rdns && host && host->h_name && host->h_name[0]) ?
5029                       (CHAR *)host->h_name : (CHAR *)ipaddr),
5030                      service->s_port,
5031                      &l_addr,&r_addr
5032                      ) < 0) {
5033             debug(F100,"rlogin initialization failed","",0);
5034             netclos();
5035             return(-1);
5036         }
5037     } else
5038 #endif /* RLOGCODE */
5039     if (tn_ini() < 0) {                 /* Start Telnet negotiations. */
5040         netclos();
5041         return(-1);                     /* Gone, so open failed.  */
5042     }
5043     if (ttchk() < 0) {
5044         netclos();
5045         return(-1);
5046     }
5047 #ifdef CK_KERBEROS
5048 #ifdef KRB5_U2U
5049    if ( ttnproto == NP_K5U2U ) {
5050        if (k5_user_to_user_client_auth()) {
5051            netclos();
5052            return(-1);
5053        }
5054    }
5055 #endif /* KRB5_U2U */
5056 #endif /* CK_KERBEROS */
5057
5058     debug(F101,"netopen service","",svcnum);
5059     debug(F110,"netopen name",name,0);
5060     debug(F110,"netopen ipaddr",ipaddr,0);
5061     ckstrncpy(hostipaddr,ipaddr,63);
5062
5063     if (lcl) if (*lcl < 0)              /* Local mode. */
5064       *lcl = 1;
5065 #endif /* TCPSOCKET */
5066     return(0);                          /* Done. */
5067 }
5068
5069 /*  N E T C L O S  --  Close current network connection.  */
5070
5071 #ifndef NOLOCAL
5072 _PROTOTYP(VOID slrestor,(VOID));
5073 #ifdef CK_SSL
5074 int tls_norestore = 0;
5075 #endif /* CK_SSL */
5076 #endif /* NOLOCAL */
5077
5078 int
5079 netclos() {
5080     static int close_in_progress = 0;
5081     int x = 0, y, z;
5082     debug(F101,"netclos","",ttyfd);
5083
5084 #ifdef NETLEBUF
5085     if (!tt_push_inited)
5086       le_init();
5087 #endif /* NETLEBUF */
5088
5089     if (ttyfd == -1)                    /* Was open? */
5090       return(0);                        /* Wasn't. */
5091
5092     if (close_in_progress)
5093       return(0);
5094     close_in_progress = 1;              /* Remember */
5095
5096 #ifndef NOLOCAL
5097     /* This function call should not be here since this is a direct call */
5098     /* from an I/O routine to a user interface level function.  However, */
5099     /* the reality is that we do not have pure interfaces.  If we ever   */
5100     /* decide to clean this up the UI level should assign this function  */
5101     /* via a pointer assignment.  - Jeff 9/10/1999                       */
5102 #ifdef CK_SSL
5103     if (!tls_norestore)
5104 #endif /* CK_SSL */
5105       slrestor();
5106 #endif /* NOLOCAL */
5107 #ifdef OS2
5108     RequestTCPIPMutex(SEM_INDEFINITE_WAIT);
5109 #else /* OS2 */
5110     if (ttyfd > -1)                     /* Was. */
5111 #endif /* OS2 */
5112       {
5113 #ifdef VMS
5114           y = 1;                          /* Turn on nonblocking reads */
5115           z = socket_ioctl(ttyfd,FIONBIO,&y);
5116           debug(F111,"netclos FIONBIO","on",z);
5117 #endif /* VMS */
5118 #ifdef TNCODE
5119           if (ttnproto == NP_TELNET) {
5120             if (!TELOPT_ME(TELOPT_LOGOUT)
5121 #ifdef COMMENT
5122 /* Jeff 2005/12/30 */
5123 #ifdef CK_SSL
5124                  && !ssl_raw_flag && !tls_raw_flag
5125 #endif  /* CK_SSL */
5126 #endif  /* COMMENT */
5127                 ) {
5128                 /* Send LOGOUT option before close */
5129                 if (tn_sopt(DO,TELOPT_LOGOUT) >= 0) {
5130                     TELOPT_UNANSWERED_DO(TELOPT_LOGOUT) = 1;
5131                     /* It would be nice to call tn_wait but we can't */
5132                 }
5133             }
5134             tn_push();                  /* Place any waiting data into input*/
5135           }
5136 #endif /* TNCODE */
5137 #ifdef CK_SSL
5138           if (ssl_active_flag) {
5139               if (ssl_debug_flag)
5140                 BIO_printf(bio_err,"calling SSL_shutdown\n");
5141               SSL_shutdown(ssl_con);
5142               ssl_active_flag = 0;
5143           }
5144           if (tls_active_flag) {
5145               if (ssl_debug_flag)
5146                 BIO_printf(bio_err,"calling SSL_shutdown\n");
5147               SSL_shutdown(tls_con);
5148               tls_active_flag = 0;
5149           }
5150 #endif /* CK_SSL */
5151 #ifdef VMS
5152           ck_cancio();                  /* Cancel any outstanding reads. */
5153 #endif /* VMS */
5154 #ifdef TCPIPLIB
5155           x = socket_close(ttyfd);      /* Close it. */
5156 #else
5157 #ifndef OS2
5158 #ifdef IBMX25
5159         if (ttnet == NET_IX25) {
5160             /* riehm: should send a disc_req - but only if link is still OK */
5161             x = x25clear();
5162             close(ttyfd);
5163             if (x25serverfd) {
5164                   /* we were the passive client of a server, now we
5165                    * go back to being the normal client.
5166                    * I hope that kermit can cope with the logic that
5167                    * there can still be a connection after netclos
5168                    * has been called.
5169                    */
5170                   ttyfd = x25serverfd;
5171                   x25serverfd = 0;
5172                   /*
5173                    * need to close the server connection too - because
5174                    * all file descriptors connected to the NPI have the
5175                    * same status.
5176                    *
5177                    * The problem is that any waiting connections get
5178                    * lost, the client doesn't realise, and hangs.
5179                    */
5180                   netclos();
5181               }
5182             x25_state = X25_CLOSED;     /* riehm: dead code? */
5183         } else
5184 #endif /* IBMX25 */
5185           x = close(ttyfd);
5186 #endif /* OS2 */
5187 #endif /* TCPIPLIB */
5188       }
5189     ttyfd = -1;                         /* Mark it as closed. */
5190     wasclosed = 1;
5191 #ifdef OS2
5192     ReleaseTCPIPMutex();
5193 #endif /* OS2 */
5194 #ifdef TNCODE
5195 #ifdef CK_FORWARD_X
5196     fwdx_close_all();                   /* Shut down any Forward X sockets */
5197 #endif /* CK_FORWARD_X */
5198     tn_reset();                   /* The Reset Telnet Option table.  */
5199     debug(F100,"netclose setting tn_init = 0","",0);
5200     tn_init = 0;                        /* Remember about telnet protocol... */
5201     sstelnet = 0;                       /* Client-side Telnet */
5202 #endif /* TNCODE */
5203     *ipaddr = '\0';                     /* Zero the IP address string */
5204     tcp_incoming = 0;                   /* No longer incoming */
5205     /* Don't reset ttnproto so that we can remember which protocol is in use */
5206
5207 #ifdef TCPIPLIB
5208 /*
5209   Empty the internal buffers so they won't be used as invalid input on
5210   the next connect attempt (rlogin).
5211 */
5212     ttibp = 0;
5213     ttibn = 0;
5214 #endif /* TCPIPLIB */
5215 #ifdef CK_KERBEROS
5216     /* If we are automatically destroying Kerberos credentials on Close */
5217     /* do it now. */
5218 #ifdef KRB4
5219     if (krb4_autodel == KRB_DEL_CL) {
5220         extern struct krb_op_data krb_op;
5221         krb_op.version = 4;
5222         krb_op.cache = NULL;
5223         ck_krb4_destroy(&krb_op);
5224     }
5225 #endif /* KRB4 */
5226 #ifdef KRB5
5227     if (krb5_autodel == KRB_DEL_CL) {
5228         extern struct krb_op_data krb_op;
5229         extern char * krb5_d_cc;
5230         krb_op.version = 5;
5231         krb_op.cache = krb5_d_cc;
5232         ck_krb5_destroy(&krb_op);
5233     }
5234 #endif /* KRB5 */
5235 #endif /* CK_KERBEROS */
5236     close_in_progress = 0;              /* Remember we are done. */
5237     return(x);
5238 }
5239
5240 #ifdef OS2
5241 int
5242 os2socketerror( int s_errno ) {
5243 #ifdef OS2ONLY
5244     if (s_errno > 0 && s_errno <= SOCBASEERR) {
5245         /* in OS/2, there is a problem with threading in that
5246          * the value of errno is not thread safe.  It can be
5247          * set to a value from a previous library call and if
5248          * it was not cleared it will appear here.  Only treat
5249          * valid socket error codes as errors in this function.
5250          */
5251         debug(F100,"os2socketerror errno.h","",0);
5252         socket_errno = 0;
5253         return(0);
5254     }
5255 #endif /* OS2ONLY */
5256
5257     switch (s_errno) {
5258       case 0:                           /* NO ERROR */
5259         debug(F100,"os2socketerror NOERROR","",0);
5260         return(0);
5261 #ifdef NT
5262       case WSAECONNRESET:
5263 #else /* NT */
5264       case SOCECONNRESET:
5265       case SOCECONNRESET - SOCBASEERR:
5266 #endif /* NT */
5267         debug(F100,"os2socketerror ECONRESET","",0);
5268         tn_debug("ECONRESET");
5269         netclos();              /* *** *** */
5270         return(-1);             /* Connection is broken. */
5271 #ifdef NT
5272       case WSAECONNABORTED:
5273 #else /* NT */
5274       case SOCECONNABORTED:
5275       case SOCECONNABORTED - SOCBASEERR:
5276 #endif /* NT */
5277         debug(F100,"os2socketerror ECONNABORTED","",0);
5278         tn_debug("ECONNABORTED");
5279         netclos();              /* *** *** */
5280         return(-1);             /* Connection is broken. */
5281 #ifdef NT
5282       case WSAENETRESET:
5283 #else /* NT */
5284       case SOCENETRESET:
5285       case SOCENETRESET - SOCBASEERR:
5286 #endif /* NT */
5287         debug(F100,"os2socketerror ENETRESET","",0);
5288         tn_debug("ENETRESET");
5289         netclos();              /* *** *** */
5290         return(-1);             /* Connection is broken. */
5291 #ifdef NT
5292       case WSAENOTCONN:
5293 #else /* NT */
5294       case SOCENOTCONN:
5295       case SOCENOTCONN - SOCBASEERR:
5296 #endif /* NT */
5297         debug(F100,"os2socketerror ENOTCONN","",0);
5298         tn_debug("ENOTCONN");
5299         netclos();                      /* *** *** */
5300         return(-1);                     /* Connection is broken. */
5301 #ifdef NT
5302       case WSAESHUTDOWN:
5303         debug(F100,"os2socketerror ESHUTDOWN","",0);
5304         tn_debug("ESHUTDOWN");
5305         netclos();                      /* *** *** */
5306         return(-1);                     /* Connection is broken. */
5307 #endif /* NT */
5308 #ifdef NT
5309       case WSAEWOULDBLOCK:
5310 #else
5311       case SOCEWOULDBLOCK:
5312       case SOCEWOULDBLOCK - SOCBASEERR:
5313 #endif /* NT */
5314         debug(F100,"os2socketerror EWOULDBLOCK","",0);
5315         return(0);
5316 #ifdef NT
5317       case ERROR_IO_INCOMPLETE:
5318       case ERROR_IO_PENDING:
5319       case ERROR_OPERATION_ABORTED:
5320         return(0);
5321 #endif /* NT */
5322       default:
5323         return(-2);
5324     }
5325     return(0);
5326 }
5327 #endif /* OS2 */
5328
5329 /*  N E T T C H K  --  Check if network up, and how many bytes can be read */
5330 /*
5331   Returns number of bytes waiting, or -1 if connection has been dropped.
5332 */
5333 int                                     /* Check how many bytes are ready */
5334 nettchk() {                             /* for reading from network */
5335 #ifdef TCPIPLIB
5336     long count = 0;
5337     int x = 0, z;
5338     long y;
5339     char c;
5340     int rc;
5341 #ifdef NT
5342     extern int ionoblock;               /* For Overlapped I/O */
5343 #endif /* NT */
5344
5345     debug(F101,"nettchk entry ttibn","",ttibn);
5346     debug(F101,"nettchk entry ttibp","",ttibp);
5347
5348 #ifdef NETLEBUF
5349     {
5350         int n = 0;
5351         if (ttpush >= 0)
5352           n++;
5353         n += le_inbuf();
5354         if (n > 0)
5355           return(n);
5356     }
5357 #endif /* NETLEBUF */
5358
5359 #ifndef OS2
5360 #ifndef BEBOX
5361     socket_errno = 0; /* This is a function call in NT, and BeOS */
5362 #endif /* BEBOX */
5363 #endif /* OS2 */
5364
5365     if (ttyfd == -1) {
5366         debug(F100,"nettchk socket is closed","",0);
5367         return(-1);
5368     }
5369 /*
5370   Note: this socket_ioctl() call does NOT return an error if the
5371   connection has been broken.  (At least not in MultiNet.)
5372 */
5373 #ifdef COMMENT
5374 /*  Another trick that can be tried here is something like this: */
5375
5376     if (ttnet == NET_TCPB) {
5377         char dummy;
5378         x = read(ttyfd,&dummy,0);       /* Try to read nothing */
5379         if (x < 0) {                    /* "Connection reset by peer" */
5380             perror("TCP/IP");           /* or somesuch... */
5381             ttclos(0);                  /* Close our end too. */
5382             return(-1);
5383         }
5384     }
5385 #endif /* COMMENT */
5386
5387
5388 #ifdef CK_SSL
5389     if (ssl_active_flag) {
5390 #ifndef IKSDONLY
5391 #ifdef OS2
5392         if ( IsConnectMode() ) {
5393             debug(F101,"nettchk (ssl_active_flag) returns","",count);
5394             return(0);
5395         }
5396 #endif /* OS2 */
5397 #endif /* IKSDONLY */
5398         count = SSL_pending(ssl_con);
5399         if (count < 0) {
5400             debug(F111,"nettchk","SSL_pending error",count);
5401             netclos();
5402             return(-1);
5403         }
5404         if ( count > 0 )
5405             return(count);                  /* Don't perform a read */
5406     } else if (tls_active_flag) {
5407 #ifndef IKSDONLY
5408 #ifdef OS2
5409         if ( IsConnectMode() ) {
5410             debug(F101,"nettchk (tls_active_flag) returns","",count);
5411             return(0);
5412         }
5413 #endif /* OS2 */
5414 #endif /* IKSDONLY */
5415         count = SSL_pending(tls_con);
5416         if (count < 0) {
5417             debug(F111,"nettchk","TLS_pending error",count);
5418             netclos();
5419             return(-1);
5420         }
5421         if ( count > 0 )
5422             return(count);                  /* Don't perform a read */
5423     } else
5424 #endif /* CK_SSL */
5425
5426     if (socket_ioctl(ttyfd,FIONREAD,
5427 #ifdef COMMENT
5428     /* Now we've changed the ioctl(..,..,x) prototype for DECC to (void *) */
5429 #ifdef __DECC
5430     /* NOTE: "&count" might need to be "(char *)&count" in some settings. */
5431                      /* Cast needed for DECC 4.1 & later? */
5432                      /* Maybe, but __DECC_VER only exists in 5.0 and later */
5433                      (char *)
5434 #endif /* __DECC */
5435 #endif /* COMMENT */
5436                      &count
5437                      ) < 0) {
5438         debug(F101,"nettchk socket_ioctl error","",socket_errno);
5439         /* If the connection is gone, the connection is gone. */
5440         netclos();
5441 #ifdef NT_TCP_OVERLAPPED
5442         /* Is there anything in the overlapped I/O buffers? */
5443         count += OverlappedDataWaiting();
5444 #endif /* NT_TCP_OVERLAPPED */
5445         count += ttibn;
5446         return(count>0?count:-1);
5447     }
5448     debug(F101,"nettchk count","",count);
5449 #ifdef NT_TCP_OVERLAPPED
5450     /* Is there anything in the overlapped I/O buffers? */
5451     count += OverlappedDataWaiting();
5452     debug(F101,"nettchk count w/overlapped","",count);
5453 #endif /* NT_TCP_OVERLAPPED */
5454
5455 #ifdef OS2
5456 #ifndef IKSDONLY
5457     if ( IsConnectMode() ) {
5458         debug(F101,"nettchk (FIONREAD) returns","",count);
5459         return(count);
5460     }
5461 #endif /* IKSDONLY */
5462 #endif /* OS2 */
5463
5464 /* For the sake of efficiency, if there is still data in the ttibuf */
5465 /* do not go to the bother of checking to see of the connection is  */
5466 /* still valid.  The handle is still good, so just return the count */
5467 /* of the bytes that we already have left to process.               */
5468 #ifdef OS2
5469     if ( count > 0 || ttibn > 0 ) {
5470         count+=ttibn;
5471         debug(F101,"nettchk (count+ttibn > 0) returns","",count);
5472         return(count);
5473     } else {
5474         RequestTCPIPMutex(SEM_INDEFINITE_WAIT);
5475         if ( ttibn == 0 )
5476             ttibp = 0;      /* reset for next read */
5477     }
5478 #else /* OS2 */
5479     if ( count > 0 || ttibn > 0 ) {
5480         debug(F101,"nettchk returns","",count+ttibn);
5481         return(count+ttibn);
5482     }
5483     ttibn = ttibp = 0;
5484 #endif /* OS2 */
5485
5486 /*
5487   The following code works well in most settings, but messes things up in
5488   others, including CMU/Tek TCP/IP and UCX 2.0, where it somehow manages to
5489   make it impossible to ever make a new connection to the same host again with
5490   CONNECT, once it has been logged out from the first time.  Not even if you
5491   HANGUP first, or SET HOST<CR>, or SET LINE<CR>.  Reportedly, however, it
5492   does work OK in later releases of UCX.  But there is no way we can
5493   accommodate both old and new -- we might have static linking or dynamic
5494   linking, etc etc.  If we have static, I only have access to 2.0, where this
5495   doesn't work, etc etc blah blah.
5496
5497   In the following lines, we define a symbol NOCOUNT for builds where we want
5498   to omit this code.  By default, it is omitted for CMU/Tek.  You can force
5499   omission of it for other combinations by defining NOCOUNT in CFLAGS.  You
5500   can force inclusion of this code, even for CMU/Tek, by including NONOCOUNT
5501   in CFLAGS.
5502 */
5503 #ifdef NONOCOUNT
5504 #ifdef NOCOUNT
5505 #undef NOCOUNT
5506 #endif /* NOCOUNT */
5507 #else
5508 #ifndef NOCOUNT
5509 #ifdef CMU_TCPIP
5510 #define NOCOUNT
5511 #endif /* CMU_TCPIP */
5512 #endif /* NOCOUNT */
5513 #endif /* NONOCOUNT */
5514
5515
5516     /* From this point forward we have a possible race condition in K95
5517      * due to its use of multiple threads.  Therefore, we must ensure
5518      * that only one thread attempt to read/write from the socket at a
5519      * time.  Otherwise, it is possible for a buffer to be overwritten.
5520      */
5521     /* we know now that count >= 0 and that ttibn == 0 */
5522
5523     if (count == 0
5524 #ifdef RLOGCODE
5525 #ifdef CK_KERBEROS
5526         && ttnproto != NP_EK4LOGIN && ttnproto != NP_EK5LOGIN
5527 #endif /* CK_KERBEROS */
5528 #endif /* RLOGCODE */
5529         ) {
5530         int s_errno = 0;
5531 #ifndef NOCOUNT
5532 /*
5533   Here we need to tell the difference between a 0 count on an active
5534   connection, and a 0 count because the remote end of the socket broke the
5535   connection.  There is no mechanism in TGV MultiNet (or WIN/TCP?) to query
5536   the status of the connection, so we have to do a read.  -1 means there was
5537   no data available (socket_errno == EWOULDBLOCK), 0 means the connection is
5538   down.  But if, by chance, we actually get a character, we have to put it
5539   where it won't be lost.
5540 */
5541 #ifndef NON_BLOCK_IO
5542 #ifdef OS2
5543 #ifdef CK_SSL
5544         RequestSSLMutex(SEM_INDEFINITE_WAIT);
5545 #endif /* CK_SSL */
5546 #endif /* OS2 */
5547         y = 1;                          /* Turn on nonblocking reads */
5548         z = socket_ioctl(ttyfd,FIONBIO,&y);
5549         debug(F111,"nettchk FIONBIO","on",z);
5550 #ifdef OS2
5551 #ifdef CK_SSL
5552         ReleaseSSLMutex();
5553 #endif /* CK_SSL */
5554 #endif /* OS2 */
5555 #endif /* NON_BLOCK_IO */
5556 #ifdef NT_TCP_OVERLAPPED
5557         ionoblock = 1;                  /* For Overlapped I/O */
5558 #endif /* NT_TCP_OVERLAPPED */
5559 #ifdef CK_SSL
5560         if ( ssl_active_flag || tls_active_flag ) {
5561 #ifdef OS2
5562           ssl_read:
5563             x = SSL_read( ssl_active_flag?ssl_con:tls_con,
5564                           &ttibuf[ttibp+ttibn],
5565                           TTIBUFL-ttibp-ttibn );
5566             switch (SSL_get_error(ssl_active_flag?ssl_con:tls_con,x)) {
5567             case SSL_ERROR_NONE:
5568                 debug(F111,"nettchk SSL_ERROR_NONE","x",x);
5569                 break;
5570             case SSL_ERROR_WANT_WRITE:
5571                 debug(F100,"nettchk SSL_ERROR_WANT_WRITE","",0);
5572                 x = -1;
5573                 break;
5574             case SSL_ERROR_WANT_READ:
5575                 debug(F100,"nettchk SSL_ERROR_WANT_READ","",0);
5576                 x = -1;
5577                 break;
5578             case SSL_ERROR_SYSCALL:
5579                 if ( x == 0 ) { /* EOF */
5580                     netclos();
5581                     rc = -1;
5582                     goto nettchk_return;
5583               } else {
5584 #ifdef NT
5585                   int gle = GetLastError();
5586 #endif /* NT */
5587 #ifndef NON_BLOCK_IO
5588 #ifdef OS2
5589 #ifdef CK_SSL
5590                   RequestSSLMutex(SEM_INDEFINITE_WAIT);
5591 #endif /* CK_SSL */
5592 #endif /* OS2 */
5593                   y = 0;                          /* Turn off nonblocking reads */
5594                   z = socket_ioctl(ttyfd,FIONBIO,&y);
5595                   debug(F111,"nettchk FIONBIO","off",z);
5596 #ifdef OS2
5597 #ifdef CK_SSL
5598                   ReleaseSSLMutex();
5599 #endif /* CK_SSL */
5600 #endif /* OS2 */
5601 #endif /* NON_BLOCK_IO */
5602 #ifdef NT_TCP_OVERLAPPED
5603                   ionoblock = 0;                  /* For Overlapped I/O */
5604 #endif /* NT_TCP_OVERLAPPED */
5605 #ifdef NT
5606                   debug(F111,"nettchk SSL_ERROR_SYSCALL",
5607                          "GetLastError()",gle);
5608                   rc = os2socketerror(gle);
5609                   if (rc == -1)
5610                       rc = -2;
5611                   else if ( rc == -2 )
5612                       rc = -1;
5613                   goto nettchk_return;
5614 #endif /* NT */
5615                   break;
5616               }
5617           case SSL_ERROR_WANT_X509_LOOKUP:
5618                 debug(F100,"nettchk SSL_ERROR_WANT_X509_LOOKUP","",0);
5619                 break;
5620             case SSL_ERROR_SSL:
5621                 if (bio_err!=NULL) {
5622                     int len;
5623                     extern char ssl_err[];
5624                     BIO_printf(bio_err,"nettchk() SSL_ERROR_SSL\n");
5625                     ERR_print_errors(bio_err);
5626                     len = BIO_read(bio_err,ssl_err,SSL_ERR_BFSZ);
5627                     ssl_err[len < SSL_ERR_BFSZ ? len : SSL_ERR_BFSZ] = '\0';
5628                     debug(F110,"nettchk SSL_ERROR_SSL",ssl_err,0);
5629                     if (ssl_debug_flag)
5630                         printf(ssl_err);
5631                 } else if (ssl_debug_flag) {
5632                     debug(F100,"nettchk SSL_ERROR_SSL","",0);
5633                     fflush(stderr);
5634                     fprintf(stderr,"nettchk() SSL_ERROR_SSL\n");
5635                     ERR_print_errors_fp(stderr);
5636                 }
5637 #ifdef COMMENT
5638                 netclos();
5639                 rc = -1;
5640                 goto nettchk_return;
5641 #else
5642                 x = -1;
5643                 break;
5644 #endif
5645           case SSL_ERROR_ZERO_RETURN:
5646                 debug(F100,"nettchk SSL_ERROR_ZERO_RETURN","",0);
5647                 netclos();
5648                 rc = -1;
5649                 goto nettchk_return;
5650             default:
5651                 debug(F100,"nettchk SSL_ERROR_?????","",0);
5652                 netclos();
5653                 rc = -1;
5654                 goto nettchk_return;
5655             }
5656 #else /* OS2 */
5657             /* Do not block */
5658             x = -1;
5659 #endif /* OS2 */
5660         } else
5661 #endif /* CK_SSL */
5662         {
5663 #ifdef OS2
5664         x = socket_read(ttyfd,&ttibuf[ttibp+ttibn],
5665                          TTIBUFL-ttibp-ttibn);  /* Returns -1 if no data */
5666 #else /* OS2 */
5667         x = socket_read(ttyfd,&c,1);    /* Returns -1 if no data */
5668 #endif /* OS2 */
5669         }
5670         s_errno = socket_errno;         /* socket_errno may be a function */
5671         debug(F101,"nettchk socket_read","",x);
5672
5673 #ifndef NON_BLOCK_IO
5674 #ifdef OS2
5675 #ifdef CK_SSL
5676         RequestSSLMutex(SEM_INDEFINITE_WAIT);
5677 #endif /* CK_SSL */
5678 #endif /* OS2 */
5679         y = 0;                          /* Turn off nonblocking reads */
5680         z = socket_ioctl(ttyfd,FIONBIO,&y);
5681         debug(F111,"nettchk FIONBIO","off",z);
5682 #ifdef OS2
5683 #ifdef CK_SSL
5684         ReleaseSSLMutex();
5685 #endif /* CK_SSL */
5686 #endif /* OS2 */
5687 #endif /* NON_BLOCK_IO */
5688 #ifdef NT_TCP_OVERLAPPED
5689         ionoblock = 0;                  /* For Overlapped I/O */
5690 #endif /* NT_TCP_OVERLAPPED */
5691
5692         if (x == -1) {
5693             debug(F101,"nettchk socket_read errno","",s_errno);
5694 #ifdef OS2
5695             if (os2socketerror(s_errno) < 0) {
5696                 rc = -1;
5697                 goto nettchk_return;
5698             }
5699 #endif /* OS2 */
5700         } else if (x == 0) {
5701             debug(F100,"nettchk connection closed","",0);
5702             netclos();                  /* *** *** */
5703             rc = -1;
5704             goto nettchk_return;
5705         }
5706         if (x >= 1) {                   /* Oops, actually got a byte? */
5707 #ifdef OS2
5708             /* In OS/2 we read directly into ttibuf[] */
5709             ckhexdump("nettchk got real data",&ttibuf[ttibp+ttibn],x);
5710             ttibn += x;
5711 #else /* OS2 */
5712 #ifdef CK_SSL
5713             if ( ssl_active_flag || tls_active_flag ) {
5714                 ckhexdump("nettchk got real data",&ttibuf[ttibp+ttibn],x);
5715                 ttibn += x;
5716             } else 
5717 #endif /* CK_SSL */
5718             {
5719                 debug(F101,"nettchk socket_read char","",c);
5720                 debug(F101,"nettchk ttibp","",ttibp);
5721                 debug(F101,"nettchk ttibn","",ttibn);
5722 /*
5723   In the case of Overlapped I/O the character would have come from
5724   the beginning of the buffer, so put it back.
5725 */
5726                 if (ttibp > 0) {
5727                     ttibp--;
5728                     ttibuf[ttibp] = c;
5729                     ttibn++;
5730                 } else {
5731                     ttibuf[ttibp+ttibn] = c;
5732                     ttibn++;
5733                 }
5734             }
5735 #endif /* OS2 */
5736         }
5737 #else /* NOCOUNT */
5738         if (ttnet == NET_TCPB) {
5739             char dummy;
5740             x = read(ttyfd,&dummy,0);   /* Try to read nothing */
5741             if (x < 0) {                /* "Connection reset by peer" */
5742                 perror("TCP/IP");       /* or somesuch... */
5743                 ttclos(0);              /* Close our end too. */
5744                 rc = -1;
5745                 goto nettchk_return;
5746             }
5747         }
5748 #endif /* NOCOUNT */
5749     }
5750 #ifdef CK_KERBEROS
5751 #ifdef KRB4
5752 #ifdef RLOGCODE
5753     if (ttnproto == NP_EK4LOGIN)
5754       count += krb4_des_avail(ttyfd);
5755 #endif /* RLOGCODE */
5756 #endif /* KRB4 */
5757 #ifdef KRB5
5758 #ifdef RLOGCODE
5759     if (ttnproto == NP_EK5LOGIN)
5760       count += krb5_des_avail(ttyfd);
5761 #endif /* RLOGCODE */
5762 #ifdef KRB5_U2U
5763     if (ttnproto == NP_K5U2U)
5764       count += krb5_u2u_avail(ttyfd);
5765 #endif /* KRB5_U2U */
5766 #endif /* KRB5 */
5767 #endif /* CK_KERBEROS */
5768
5769     debug(F101,"nettchk returns","",count+ttibn);
5770     rc = count + ttibn;
5771
5772   nettchk_return:
5773 #ifdef OS2
5774     ReleaseTCPIPMutex();
5775 #endif /* OS2 */
5776     return(rc);
5777
5778 #else /* Not TCPIPLIB */
5779 /*
5780   UNIX just uses ttchk(), in which the ioctl() calls on the file descriptor
5781   seem to work OK.
5782 */
5783     return(ttchk());
5784 #endif /* TCPIPLIB */
5785 /*
5786   But what about X.25?
5787 */
5788 }
5789
5790 #ifndef OS2
5791 VOID
5792 nettout(i) int i; {                     /* Catch the alarm interrupts */
5793     debug(F100,"nettout caught timeout","",0);
5794     ttimoff();
5795     cklongjmp(njbuf, -1);
5796 }
5797 #endif /* !OS2 */
5798
5799 #ifdef TCPIPLIB
5800
5801 VOID
5802 #ifdef CK_ANSIC
5803 donetinc(void * threadinfo)
5804 #else /* CK_ANSIC */
5805 donetinc(threadinfo) VOID * threadinfo;
5806 #endif /* CK_ANSIC */
5807 /* donetinc */ {
5808 #ifdef NTSIG
5809     extern int TlsIndex;
5810     setint();
5811     if (threadinfo) {                   /* Thread local storage... */
5812         TlsSetValue(TlsIndex,threadinfo);
5813     }
5814 #endif /* NTSIG */
5815 #ifdef CK_LOGIN
5816 #ifdef NT
5817 #ifdef IKSD
5818     if (inserver)
5819       setntcreds();
5820 #endif /* IKSD */
5821 #endif /* NT */
5822 #endif /* CK_LOGIN */
5823     while (1) {
5824         if (ttbufr() < 0)               /* Keep trying to refill it. */
5825           break;                        /* Till we get an error. */
5826         if (ttibn > 0)                  /* Or we get a character. */
5827           break;
5828     }
5829 }
5830 #endif /* TCPIPLIB */
5831
5832 VOID
5833 #ifdef CK_ANSIC
5834 failnetinc(void * threadinfo)
5835 #else /* CK_ANSIC */
5836 failnetinc(threadinfo) VOID * threadinfo;
5837 #endif /* CK_ANSIC */
5838 /* failnetinc */ {
5839     ; /* Nothing to do on an error */
5840 }
5841
5842 /* N E T X I N -- Input block of characters from network */
5843
5844 int
5845 netxin(n,buf) int n; CHAR * buf; {
5846     int len, i, j;
5847 #ifdef TCPIPLIB
5848     int rc;
5849 #endif /* TCPIPLIB */
5850
5851     if (ttyfd == -1) {
5852         debug(F100,"netxin socket is closed","",0);
5853         return(-2);
5854     }
5855 #ifdef CK_KERBEROS
5856 #ifdef KRB4
5857 #ifdef RLOGCODE
5858     if (ttnproto == NP_EK4LOGIN) {
5859         if ((len = krb4_des_read(ttyfd,buf,n)) < 0)
5860           return(-1);
5861         else
5862           return(len);
5863     }
5864 #endif /* RLOGCODE */
5865 #endif /* KRB4 */
5866 #ifdef KRB5
5867 #ifdef RLOGCODE
5868     if (ttnproto == NP_EK5LOGIN) {
5869         if ((len = krb5_des_read(ttyfd,(char *)buf,n,0)) < 0)
5870           return(-1);
5871         else
5872           return(len);
5873     }
5874 #endif /* RLOGCODE */
5875 #ifdef KRB5_U2U
5876     if (ttnproto == NP_K5U2U) {
5877         if ((len = krb5_u2u_read(ttyfd,(char *)buf,n)) < 0)
5878           return(-1);
5879         else
5880           return(len);
5881     }
5882 #endif /* KRB5_U2U */
5883 #endif /* KRB5 */
5884 #endif /* CK_KERBEROS */
5885
5886 #ifdef TCPIPLIB
5887 #ifdef OS2
5888     RequestTCPIPMutex(SEM_INDEFINITE_WAIT);
5889 #endif /* OS2 */
5890     if (ttibn == 0)
5891       if ((rc = ttbufr()) <= 0) {
5892 #ifdef OS2
5893         ReleaseTCPIPMutex();
5894 #endif /* OS2 */
5895         return(rc);
5896       }
5897
5898     if (ttibn <= n) {
5899         len = ttibn;
5900         memcpy(buf,&ttibuf[ttibp],len);         /* safe */
5901         ttibp += len;
5902         ttibn = 0;
5903     } else {
5904         memcpy(buf,&ttibuf[ttibp],n);           /* safe */
5905         ttibp += n;
5906         ttibn -= n;
5907         len = n;
5908     }
5909 #ifdef OS2
5910     ReleaseTCPIPMutex();
5911 #endif /* OS2 */
5912 #else /* TCPIPLIB */
5913     for (i = 0; i < n; i++) {
5914         if ((j = netinc(0)) < 0) {
5915             if (j < -1)
5916               return(j);
5917             else
5918               break;
5919         }
5920         buf[i] = j;
5921     }
5922     len = i;
5923 #endif /* TCPIPLIB */
5924
5925 #ifdef COMMENT
5926 #ifdef CK_ENCRYPTION
5927     /* This would be great if it worked.  But what if the buffer we read  */
5928     /* contains a telnet negotiation that changes the state of the        */
5929     /* encryption.  If so, we would be either decrypting unencrypted text */
5930     /* or not decrypting encrypted text.  So we must move this call to    */
5931     /* all functions that call ttxin().  In OS2 that means os2_netxin()   */
5932     /* where the Telnet Negotiations are handled.                         */
5933     if (u_encrypt)
5934       ck_tn_decrypt(buf,len);
5935 #endif /* CK_ENCRYPTION */
5936 #endif /* COMMENT */
5937
5938     return(len);
5939 }
5940
5941 /*  N E T I N C --  Input character from network */
5942
5943 #ifdef NETLEBUF
5944 #define LEBUF
5945 #endif /* NETLEBUF */
5946 #ifdef TTLEBUF
5947 #define LEBUF
5948 #endif /* TTLEBUF */
5949 #ifndef LEBUF
5950 #ifdef OS2
5951 #define LEBUF
5952 #endif /* OS2 */
5953 #endif /* LEBUF */
5954
5955 int
5956 netinc(timo) int timo; {
5957 #ifdef TCPIPLIB
5958     int x; unsigned char c;             /* The locals. */
5959
5960 #ifdef NETLEBUF
5961     if (ttpush >= 0) {
5962         debug(F111,"netinc","ttpush",ttpush);
5963         c = ttpush;
5964         ttpush = -1;
5965         return(c);
5966     }
5967     if (le_data) {
5968         if (le_getchar((CHAR *)&c) > 0) {
5969             debug(F111,"netinc le_getchar","c",c);
5970             return(c);
5971         }
5972     }
5973 #endif /* NETLEBUF */
5974
5975     if (ttyfd == -1) {
5976         debug(F100,"netinc socket is closed","",0);
5977         return(-2);
5978     }
5979
5980 #ifdef CK_KERBEROS
5981 #ifdef KRB4
5982 #ifdef RLOGCODE
5983     if (ttnproto == NP_EK4LOGIN) {
5984         if ((x = krb4_des_read(ttyfd,&c,1)) == 0)
5985           return(-1);
5986         else if (x < 0)
5987           return(-2);
5988         else
5989           return(c);
5990     }
5991 #endif /* RLOGCODE */
5992 #endif /* KRB4 */
5993 #ifdef KRB5
5994 #ifdef RLOGCODE
5995     if (ttnproto == NP_EK5LOGIN) {
5996         if ((x = krb5_des_read(ttyfd,&c,1,0)) == 0)
5997           return(-1);
5998         else if (x < 0)
5999           return(-2);
6000         else
6001           return(c);
6002     }
6003 #endif /* RLOGCODE */
6004 #ifdef KRB5_U2U
6005     if (ttnproto == NP_K5U2U) {
6006         if ((x = krb5_u2u_read(ttyfd,&c,1)) == 0)
6007           return(-1);
6008         else if (x < 0)
6009           return(-2);
6010         else
6011           return(c);
6012     }
6013 #endif /* KRB5_U2U */
6014 #endif /* KRB5 */
6015 #endif /* CK_KERBEROS */
6016
6017 #ifdef OS2
6018     RequestTCPIPMutex(SEM_INDEFINITE_WAIT);
6019 #endif /* OS2 */
6020     if (ttibn > 0) {                    /* Something in internal buffer? */
6021 #ifdef COMMENT
6022         debug(F100,"netinc char in buf","",0); /* Yes. */
6023 #endif /* COMMENT */
6024         x = 0;                          /* Success. */
6025     } else {                            /* Else must read from network. */
6026         x = -1;                         /* Assume failure. */
6027 #ifdef DEBUG
6028         debug(F101,"netinc goes to net, timo","",timo);
6029 #endif /* DEBUG */
6030 #ifdef CK_SSL
6031         /*
6032          * In the case of OpenSSL, it is possible that there is still
6033          * data waiting in the SSL session buffers that has not yet
6034          * been read by Kermit.  If this is the case we must process
6035          * it without calling select() because select() will not return
6036          * with an indication that there is data to be read from the
6037          * socket.  If there is no data pending in the SSL session
6038          * buffers then fall through to the select() code and wait for
6039          * some data to arrive.
6040          */
6041         if (ssl_active_flag) {
6042             x = SSL_pending(ssl_con);
6043             if (x < 0) {
6044                 debug(F111,"netinc","SSL_pending error",x);
6045                 netclos();
6046 #ifdef OS2
6047                 ReleaseTCPIPMutex();
6048 #endif /* OS2 */
6049                 return(-1);
6050             } else if ( x > 0 ) {
6051                 if ( ttbufr() >= 0 ) {
6052                     x = netinc(timo);
6053 #ifdef OS2
6054                     ReleaseTCPIPMutex();
6055 #endif /* OS2 */
6056                     return(x);
6057                 }
6058             }
6059             x = -1;
6060         } else if (tls_active_flag) {
6061             x = SSL_pending(tls_con);
6062             if (x < 0) {
6063                 debug(F111,"netinc","TLS_pending error",x);
6064                 netclos();
6065 #ifdef OS2
6066                 ReleaseTCPIPMutex();
6067 #endif /* OS2 */
6068                 return(-1);
6069             } else if ( x > 0 ) {
6070                 if ( ttbufr() >= 0 ) {
6071                     x = netinc(timo);
6072 #ifdef OS2
6073                     ReleaseTCPIPMutex();
6074 #endif /* OS2 */
6075                     return(x);
6076                 }
6077             }
6078             x = -1;
6079         }
6080 #endif /* CK_SSL */
6081 #ifndef LEBUF
6082         if (timo == 0) {                /* Untimed case. */
6083             while (1) {                 /* Wait forever if necessary. */
6084                 if (ttbufr() < 0)       /* Refill buffer. */
6085                   break;                /* Error, fail. */
6086                 if (ttibn > 0) {        /* Success. */
6087                     x = 0;
6088                     break;
6089                 }
6090             }
6091         } else                          /* Timed case... */
6092 #endif /* LEBUF */
6093           {
6094 #ifdef NT_TCP_OVERLAPPED
6095             /* This code is for use on NT when we are using */
6096             /* Overlapped I/O to handle reads.  In the case */
6097             /* of outstanding reads select() doesn't work   */
6098
6099             if (WaitForOverlappedReadData(timo)) {
6100                 while (1) {
6101                     if (ttbufr() < 0)   /* Keep trying to refill it. */
6102                         break;          /* Till we get an error. */
6103                     if (ttibn > 0) {    /* Or we get a character. */
6104                         x = 0;
6105                         break;
6106                     }
6107                 }
6108             }
6109 #else /* NT_TCP_OVERLAPPED */
6110 #ifdef BSDSELECT
6111             fd_set rfds;
6112             struct timeval tv;
6113             int timeout = timo < 0 ? -timo : 1000 * timo;
6114             debug(F101,"netinc BSDSELECT","",timo);
6115
6116             for ( ; timeout >= 0; timeout -= (timo ? 100 : 0)) {
6117                 int rc;
6118                 debug(F111,"netinc","timeout",timeout);
6119                 /* Don't move select() initialization out of the loop. */
6120                 FD_ZERO(&rfds);
6121                 FD_SET(ttyfd, &rfds);
6122                 tv.tv_sec  = tv.tv_usec = 0L;
6123                 if (timo)
6124                   tv.tv_usec = (long) 100000L;
6125                 else
6126                   tv.tv_sec = 30;
6127 #ifdef NT
6128                 WSASafeToCancel = 1;
6129 #endif /* NT */
6130                 rc = select(FD_SETSIZE,
6131 #ifdef __DECC
6132 #ifdef INTSELECT
6133                             (int *)
6134 #else /* def INTSELECT */
6135                             (fd_set *)
6136 #endif /* def INTSELECT [else] */
6137 #else /* def __DECC */
6138                             (fd_set *)
6139 #endif /* def __DECC [else] */
6140                             &rfds, NULL, NULL, &tv);
6141                 if (rc < 0) {
6142                     int s_errno = socket_errno;
6143                     debug(F111,"netinc","select",rc);
6144                     debug(F111,"netinc","socket_errno",s_errno);
6145                     if (s_errno) {
6146 #ifdef OS2
6147                         ReleaseTCPIPMutex();
6148 #endif /* OS2 */
6149                         return(-1);
6150                     }
6151                 }
6152                 debug(F111,"netinc","select",rc);
6153 #ifdef NT
6154                 WSASafeToCancel = 0;
6155 #endif /* NT */
6156                 if (!FD_ISSET(ttyfd, &rfds)) {
6157 #ifdef LEBUF
6158                     if (le_inbuf() > 0) {
6159                         timeout = -1;
6160                         break;
6161                     }
6162 #endif /* LEBUF */
6163                     /* If waiting forever we have no way of knowing if the */
6164                     /* socket closed so try writing a 0-length TCP packet  */
6165                     /* which should force an error if the socket is closed */
6166                     if (!timo) {
6167                         if ((rc = socket_write(ttyfd,"",0)) < 0) {
6168                             int s_errno = socket_errno;
6169                             debug(F101,"netinc socket_write error","",s_errno);
6170 #ifdef OS2
6171                             if (os2socketerror(s_errno) < 0) {
6172                               ReleaseTCPIPMutex();
6173                               return(-2);
6174                             }
6175                             ReleaseTCPIPMutex();
6176 #endif /* OS2 */
6177                             return(-1); /* Call it an i/o error */
6178                         }
6179                     }
6180                     continue;
6181                 }
6182                 while (1) {
6183                     if (ttbufr() < 0) { /* Keep trying to refill it. */
6184                         timeout = -1;
6185                         break;          /* Till we get an error. */
6186                     }
6187                     if (ttibn > 0) {    /* Or we get a character. */
6188                         x = 0;
6189                         timeout = -1;
6190                         break;
6191                     }
6192                 }
6193             }
6194 #ifdef NT
6195             WSASafeToCancel = 0;
6196 #endif /* NT */
6197 #else /* !BSDSELECT */
6198 #ifdef IBMSELECT
6199 /*
6200   Was used by OS/2, currently not used, but might come in handy some day...
6201   ... and it came in handy!  For our TCP/IP layer, it avoids all the fd_set
6202   and timeval stuff since this is the only place where it is used.
6203 */
6204             int socket = ttyfd;
6205             int timeout = timo < 0 ? -timo : 1000 * timo;
6206
6207             debug(F101,"netinc IBMSELECT","",timo);
6208             for ( ; timeout >= 0; timeout -= (timo ? 100 : 0)) {
6209                 if (select(&socket, 1, 0, 0, 100L) == 1) {
6210                     while (1) {
6211                         if (ttbufr() < 0) { /* Keep trying to refill it. */
6212                             timeout = -1;
6213                             break;      /* Till we get an error. */
6214                         }
6215                         if (ttibn > 0) { /* Or we get a character. */
6216                             x = 0;
6217                             timeout = -1;
6218                             break;
6219                         }
6220                     }
6221                 }
6222 #ifdef LEBUF
6223                 else if (le_inbuf() > 0)  {
6224                     timeout = -1;
6225                     break;
6226                 }
6227 #endif /* LEBUF */
6228             }
6229 #else /* !IBMSELECT */
6230 #ifdef WINSOCK
6231        /* Actually, under WinSock we have a better mechanism than select() */
6232        /* for setting timeouts (SO_RCVTIMEO, SO_SNDTIMEO) */
6233             SOCKET socket = ttyfd;
6234             debug(F101,"netinc NTSELECT","",timo);
6235             if (setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, (char *)&timo,
6236                             sizeof(timo))  == NO_ERROR)
6237               while (1) {
6238                   if (ttbufr() < 0)     /* Keep trying to refill it. */
6239                     break;              /* Till we get an error. */
6240                   if (ttibn > 0) {      /* Or we get a character. */
6241                       x = 0;
6242                       break;
6243                   }
6244               }
6245 #else /* WINSOCK */
6246 /*
6247   If we can't use select(), then we use the regular alarm()/signal()
6248   timeout mechanism.
6249 */
6250             debug(F101,"netinc alarm","",timo);
6251             x = alrm_execute(ckjaddr(njbuf),timo,nettout,donetinc,failnetinc);
6252             ttimoff();                  /* Timer off. */
6253 #endif /* WINSOCK */
6254 #endif /* IBMSELECT */
6255 #endif /* BSDSELECT */
6256 #endif /* NT_TCP_OVERLAPPED */
6257         }
6258     }
6259
6260 #ifdef LEBUF
6261     if (le_inbuf() > 0) {               /* If data was inserted into the */
6262         if (le_getchar((CHAR *)&c) > 0) {/* Local Echo buffer while the   */
6263 #ifdef OS2                               /* was taking place do not mix   */
6264           ReleaseTCPIPMutex();           /* the le data with the net data */
6265 #endif /* OS2 */
6266           return(c);
6267         }
6268     }
6269 #endif /* LEBUF */
6270     if (x < 0) {                        /* Return -1 if we failed. */
6271         debug(F100,"netinc timed out","",0);
6272 #ifdef OS2
6273         ReleaseTCPIPMutex();
6274 #endif /* OS2 */
6275         return(-1);
6276     } else {                            /* Otherwise */
6277         c = ttibuf[ttibp];              /* Return the first char in ttibuf[] */
6278         if (deblog) {
6279 #ifndef COMMENT
6280             debug(F101,"netinc returning","",c);
6281 #endif /* COMMENT */
6282             if (c == 0) {
6283                 debug(F101,"netinc 0 ttibn","",ttibn);
6284                 debug(F101,"netinc 0 ttibp","",ttibp);
6285 #ifdef BETADEBUG
6286                 {
6287 #ifdef OS2
6288                     extern int tt_type_mode;
6289                     if ( !ISVTNT(tt_type_mode) )
6290 #endif /* OS2 */
6291                     ckhexdump("netinc &ttbuf[ttibp]",&ttibuf[ttibp],ttibn);
6292                 }
6293 #endif /* BETADEBUG */
6294             }
6295         }
6296         ttibp++;
6297         ttibn--;
6298 #ifdef OS2
6299         ReleaseTCPIPMutex();
6300 #endif /* OS2 */
6301 #ifdef CK_ENCRYPTION
6302         if (TELOPT_U(TELOPT_ENCRYPTION))
6303           ck_tn_decrypt(&c,1);
6304 #endif /* CK_ENCRYPTION */
6305         return(c);
6306     }
6307 #else /* Not using TCPIPLIB */
6308     return(-1);
6309 #endif /* TCPIPLIB */
6310 }
6311
6312 /*  N E T T O L  --  Output a string of bytes to the network  */
6313 /*
6314   Call with s = pointer to string, n = length.
6315   Returns number of bytes actually written on success, or
6316   -1 on i/o error, -2 if called improperly.
6317 */
6318
6319 int
6320 nettol(s,n) CHAR *s; int n; {
6321 #ifdef TCPIPLIB
6322     int count = 0;
6323     int len = n;
6324     int try = 0;
6325
6326     if (ttyfd == -1) {
6327         debug(F100,"nettol socket is closed","",0);
6328         return -1;
6329     }
6330     debug(F101,"nettol TCPIPLIB ttnet","",ttnet);
6331 #ifdef COMMENT
6332     ckhexdump("nettol",s,n);
6333 #endif /* COMMENT */
6334
6335 #ifdef CK_KERBEROS
6336 #ifdef KRB4
6337 #ifdef RLOGCODE
6338     if (ttnproto == NP_EK4LOGIN) {
6339         return(krb4_des_write(ttyfd,s,n));
6340     }
6341 #endif /* RLOGCODE */
6342 #endif /* KRB4 */
6343 #ifdef KRB5
6344 #ifdef RLOGCODE
6345     if (ttnproto == NP_EK5LOGIN) {
6346         return(krb5_des_write(ttyfd,s,n,0));
6347     }
6348 #endif /* RLOGCODE */
6349 #ifdef KRB5_U2U
6350     if (ttnproto == NP_K5U2U) {
6351         return(krb5_u2u_write(ttyfd,s,n));
6352     }
6353 #endif /* KRB5_U2U */
6354 #endif /* KRB5 */
6355 #endif /* CK_KERBEROS */
6356
6357 #ifdef CK_ENCRYPTION
6358     if (TELOPT_ME(TELOPT_ENCRYPTION))
6359       ck_tn_encrypt(s,n);
6360 #endif /* CK_ENCRYPTION */
6361
6362 #ifdef CK_SSL
6363     if (ssl_active_flag || tls_active_flag) {
6364         int error, r;
6365         /* Write using SSL */
6366       ssl_retry:
6367         if (ssl_active_flag)
6368           r = SSL_write(ssl_con, s, len /* >1024?1024:len */);
6369         else
6370           r = SSL_write(tls_con, s, len /* >1024?1024:len */);
6371         switch (SSL_get_error(ssl_active_flag?ssl_con:tls_con,r)) {
6372           case SSL_ERROR_NONE:
6373             debug(F111,"nettol","SSL_write",r);
6374             if ( r == len )
6375                 return(n);
6376              s += r;
6377              len -= r;
6378              goto ssl_retry;
6379           case SSL_ERROR_WANT_WRITE:
6380             debug(F100,"nettol SSL_ERROR_WANT_WRITE","",0);
6381             return(-1);
6382           case SSL_ERROR_WANT_READ:
6383             debug(F100,"nettol SSL_ERROR_WANT_READ","",0);
6384             return(-1);
6385           case SSL_ERROR_SYSCALL:
6386               if ( r == 0 ) { /* EOF */
6387                   netclos();
6388                   return(-2);
6389               } else {
6390                   int rc = -1;
6391 #ifdef NT
6392                   int gle = GetLastError();
6393                   debug(F111,"nettol SSL_ERROR_SYSCALL",
6394                          "GetLastError()",gle);
6395                   rc = os2socketerror(gle);
6396                   if (rc == -1)
6397                       rc = -2;
6398                   else if ( rc == -2 )
6399                       rc = -1;
6400 #endif /* NT */
6401                   return(rc);
6402               }
6403           case SSL_ERROR_WANT_X509_LOOKUP:
6404             debug(F100,"nettol SSL_ERROR_WANT_X509_LOOKUP","",0);
6405             netclos();
6406             return(-2);
6407           case SSL_ERROR_SSL:
6408             debug(F100,"nettol SSL_ERROR_SSL","",0);
6409               if (bio_err!=NULL) {
6410                   int len;
6411                   extern char ssl_err[];
6412                   BIO_printf(bio_err,"nettol() SSL_ERROR_SSL\n");
6413                   ERR_print_errors(bio_err);
6414                   len = BIO_read(bio_err,ssl_err,SSL_ERR_BFSZ);
6415                   ssl_err[len < SSL_ERR_BFSZ ? len : SSL_ERR_BFSZ] = '\0';
6416                   debug(F110,"nettol SSL_ERROR_SSL",ssl_err,0);
6417                   if (ssl_debug_flag)
6418                       printf(ssl_err);
6419               } else if (ssl_debug_flag) {
6420                   debug(F100,"nettol SSL_ERROR_SSL","",0);
6421                   fflush(stderr);
6422                   fprintf(stderr,"nettol() SSL_ERROR_SSL\n");
6423                   ERR_print_errors_fp(stderr);
6424               }
6425 #ifdef COMMENT
6426               netclos();
6427               return(-2);
6428 #else
6429               return(-1);
6430 #endif
6431           case SSL_ERROR_ZERO_RETURN:
6432             debug(F100,"nettol SSL_ERROR_ZERO_RETURN","",0);
6433             netclos();
6434             return(-2);
6435           default:
6436             debug(F100,"nettol SSL_ERROR_?????","",0);
6437             netclos();
6438             return(-2);
6439         }
6440     }
6441 #endif /* CK_SSL */
6442
6443   nettol_retry:
6444     try++;                              /* Increase the try counter */
6445
6446     if (ttnet == NET_TCPB) {
6447 #ifdef BSDSELECT
6448         fd_set wfds;
6449         struct timeval tv;
6450
6451         debug(F101,"nettol BSDSELECT","",0);
6452         tv.tv_usec = 0L;
6453         tv.tv_sec=30;
6454 #ifdef NT
6455         WSASafeToCancel = 1;
6456 #endif /* NT */
6457 #ifdef STREAMING
6458       do_select:
6459 #endif /* STREAMING */
6460         FD_ZERO(&wfds);
6461         FD_SET(ttyfd, &wfds);
6462         if (select(FD_SETSIZE, NULL,
6463 #ifdef __DECC
6464 #ifndef __DECC_VER
6465                     (int *)
6466 #endif /* __DECC_VER */
6467 #endif /* __DECC */
6468                    &wfds, NULL, &tv) < 0) {
6469             int s_errno = socket_errno;
6470             debug(F101,"nettol select failed","",s_errno);
6471 #ifdef BETADEBUG
6472             printf("nettol select failed: %d\n", s_errno);
6473 #endif /* BETADEBUG */
6474 #ifdef NT
6475             WSASafeToCancel = 0;
6476             if (!win95selectbug)
6477 #endif /* NT */
6478               return(-1);
6479         }
6480         if (!FD_ISSET(ttyfd, &wfds)) {
6481 #ifdef STREAMING
6482             if (streaming)
6483               goto do_select;
6484 #endif /* STREAMING */
6485             debug(F111,"nettol","!FD_ISSET",ttyfd);
6486 #ifdef NT
6487             WSASafeToCancel = 0;
6488             if (!win95selectbug)
6489 #endif /* NT */
6490               return(-1);
6491         }
6492 #ifdef NT
6493         WSASafeToCancel = 0;
6494 #endif /* NT */
6495 #else /* BSDSELECT */
6496 #ifdef IBMSELECT
6497         {
6498             int tries = 0;
6499             debug(F101,"nettol IBMSELECT","",0);
6500             while (select(&ttyfd, 0, 1, 0, 1000) != 1) {
6501                 int count;
6502                 if (tries++ >= 60) {
6503                     /* if after 60 seconds we can't get permission to write */
6504                     debug(F101,"nettol select failed","",socket_errno);
6505                     return(-1);
6506                 }
6507                 if ((count = nettchk()) < 0) {
6508                     debug(F111,"nettol","nettchk()",count);
6509                     return(count);
6510                 }
6511             }
6512         }
6513 #endif /* IBMSELECT */
6514 #endif /* BSDSELECT */
6515         if ((count = socket_write(ttyfd,s,n)) < 0) {
6516             int s_errno = socket_errno; /* maybe a function */
6517             debug(F101,"nettol socket_write error","",s_errno);
6518 #ifdef OS2
6519             if (os2socketerror(s_errno) < 0)
6520               return(-2);
6521 #endif /* OS2 */
6522             return(-1);                 /* Call it an i/o error */
6523         }
6524         if (count < n) {
6525             debug(F111,"nettol socket_write",s,count);
6526             if (try > 25) {
6527                 /* don't try more than 25 times */
6528                 debug(F100,"nettol tried more than 25 times","",0);
6529                 return(-1);
6530             }
6531             if (count > 0) {
6532                 s += count;
6533                 n -= count;
6534             }
6535             debug(F111,"nettol retry",s,n);
6536             goto nettol_retry;
6537         } else {
6538             debug(F111,"nettol socket_write",s,count);
6539             return(len); /* success - return total length */
6540         }
6541     } else
6542       return(-2);
6543 #else
6544     debug(F100,"nettol TCPIPLIB not defined","",0);
6545     return(-2);
6546 #endif /* TCPIPLIB */
6547 }
6548
6549 /*  N E T T O C  --   Output character to network */
6550 /*
6551   Call with character to be transmitted.
6552   Returns 0 if transmission was successful, or
6553   -1 upon i/o error, or -2 if called improperly.
6554 */
6555 int
6556 #ifdef CK_ANSIC
6557 nettoc(CHAR c)
6558 #else
6559 nettoc(c) CHAR c;
6560 #endif /* CK_ANSIC */
6561 /* nettoc */ {
6562 #ifdef UNIX
6563     return(ttoc(c));
6564 #else
6565 #ifdef TCPIPLIB
6566     unsigned char cc;
6567     if (ttyfd == -1) {
6568         debug(F100,"nettoc socket is closed","",0);
6569         return -1;
6570     }
6571     cc = c;
6572     debug(F101,"nettoc cc","",cc);
6573
6574 #ifdef CK_KERBEROS
6575 #ifdef KRB4
6576 #ifdef RLOGCODE
6577     if (ttnproto == NP_EK4LOGIN) {
6578         return(krb4_des_write(ttyfd,&cc,1)==1?0:-1);
6579     }
6580 #endif /* RLOGCODE */
6581 #endif /* KRB4 */
6582 #ifdef KRB5
6583 #ifdef RLOGCODE
6584     if (ttnproto == NP_EK5LOGIN) {
6585         return(krb5_des_write(ttyfd,&cc,1,0)==1?0:-1);
6586     }
6587 #endif /* RLOGCODE */
6588 #ifdef KRB5_U2U
6589     if (ttnproto == NP_K5U2U) {
6590         return(krb5_u2u_write(ttyfd,&cc,1)==1?0:-1);
6591     }
6592 #endif /* KRB5_U2U */
6593 #endif /* KRB5 */
6594 #endif /* CK_KERBEROS */
6595
6596 #ifdef CK_ENCRYPTION
6597         if ( TELOPT_ME(TELOPT_ENCRYPTION) )
6598             ck_tn_encrypt(&cc,1);
6599 #endif /* CK_ENCRYPTION */
6600 #ifdef CK_SSL
6601     if (ssl_active_flag || tls_active_flag) {
6602         int len, error;
6603         /* Write using SSL */
6604       ssl_retry:
6605         if (ssl_active_flag)
6606           len = SSL_write(ssl_con, &cc, 1);
6607         else
6608           len = SSL_write(tls_con, &cc, 1);
6609         switch (SSL_get_error(ssl_active_flag?ssl_con:tls_con,len)) {
6610           case SSL_ERROR_NONE:
6611             debug(F111,"nettoc","SSL_write",len);
6612             return(len == 1 ? 0 : -1);
6613           case SSL_ERROR_WANT_WRITE:
6614           case SSL_ERROR_WANT_READ:
6615             return(-1);
6616           case SSL_ERROR_SYSCALL:
6617               if ( len == 0 ) { /* EOF */
6618                   netclos();
6619                   return(-2);
6620               } else {
6621                   int rc = -1;
6622 #ifdef NT
6623                   int gle = GetLastError();
6624                   debug(F111,"nettoc SSL_ERROR_SYSCALL",
6625                          "GetLastError()",gle);
6626                   rc = os2socketerror(gle);
6627                   if (rc == -1)
6628                       rc = -2;
6629                   else if ( rc == -2 )
6630                       rc = -1;
6631 #endif /* NT */
6632                   return(rc);
6633               }
6634         case SSL_ERROR_SSL:
6635               if (bio_err!=NULL) {
6636                   int len;
6637                   extern char ssl_err[];
6638                   BIO_printf(bio_err,"nettoc() SSL_ERROR_SSL\n");
6639                   ERR_print_errors(bio_err);
6640                   len = BIO_read(bio_err,ssl_err,SSL_ERR_BFSZ);
6641                   ssl_err[len < SSL_ERR_BFSZ ? len : SSL_ERR_BFSZ] = '\0';
6642                   debug(F110,"nettoc SSL_ERROR_SSL",ssl_err,0);
6643                   if (ssl_debug_flag)
6644                       printf(ssl_err);
6645               } else if (ssl_debug_flag) {
6646                   debug(F100,"nettoc SSL_ERROR_SSL","",0);
6647                   fflush(stderr);
6648                   fprintf(stderr,"nettoc() SSL_ERROR_SSL\n");
6649                   ERR_print_errors_fp(stderr);
6650               }
6651               return(-1);
6652               break;
6653           case SSL_ERROR_WANT_X509_LOOKUP:
6654           case SSL_ERROR_ZERO_RETURN:
6655           default:
6656             netclos();
6657             return(-2);
6658         }
6659     }
6660 #endif /* CK_SSL */
6661     if (ttnet == NET_TCPB) {
6662 #ifdef BSDSELECT
6663         fd_set wfds;
6664         struct timeval tv;
6665
6666         debug(F101,"nettoc BSDSELECT","",0);
6667         tv.tv_usec = 0L;
6668         tv.tv_sec = 30;
6669
6670 #ifdef STREAMING
6671       do_select:
6672 #endif /* STREAMING */
6673
6674         FD_ZERO(&wfds);
6675         FD_SET(ttyfd, &wfds);
6676         if (select(FD_SETSIZE, NULL,
6677 #ifdef __DECC
6678 #ifndef __DECC_VER
6679                    (int *)
6680 #endif /* __DECC_VER */
6681 #endif /* __DECC */
6682                    &wfds, NULL, &tv) < 0) {
6683             int s_errno = socket_errno;
6684             debug(F101,"nettoc select failed","",s_errno);
6685 #ifdef BETADEBUG
6686             printf("nettoc select failed: %d\n", s_errno);
6687 #endif /* BETADEBUG */
6688 #ifdef NT
6689             WSASafeToCancel = 0;
6690             if (!win95selectbug)
6691 #endif /* NT */
6692               return(-1);
6693         }
6694         if (!FD_ISSET(ttyfd, &wfds)) {
6695 #ifdef STREAMING
6696             if (streaming)
6697               goto do_select;
6698 #endif /* STREAMING */
6699             debug(F111,"nettoc","!FD_ISSET",ttyfd);
6700 #ifdef NT
6701             WSASafeToCancel = 0;
6702             if (!win95selectbug)
6703 #endif /* NT */
6704               return(-1);
6705         }
6706 #ifdef NT
6707         WSASafeToCancel = 0;
6708 #endif /* NT */
6709 #else /* BSDSELECT */
6710 #ifdef IBMSELECT
6711         {
6712             int tries = 0;
6713             while (select(&ttyfd, 0, 1, 0, 1000) != 1) {
6714                 int count;
6715                 if (tries++ >= 60) {
6716                     /* if after 60 seconds we can't get permission to write */
6717                     debug(F101,"nettoc select failed","",socket_errno);
6718                     return(-1);
6719                 }
6720                 if ((count = nettchk()) < 0) {
6721                     debug(F111,"nettoc","nettchk()",count);
6722                     return(count);
6723                 }
6724             }
6725         }
6726 #endif /* IBMSELECT */
6727 #endif /* BSDSELECT */
6728         if (socket_write(ttyfd,&cc,1) < 1) {
6729             int s_errno = socket_errno;         /* maybe a function */
6730             debug(F101,"nettoc socket_write error","",s_errno);
6731 #ifdef OS2
6732             if (os2socketerror(s_errno) < 0)
6733               return(-2);
6734 #endif /* OS2 */
6735             return(-1);
6736         }
6737         debug(F101,"nettoc socket_write","", cc);
6738         return(0);
6739     } else return(-2);
6740 #else
6741     return(-2);
6742 #endif /* TCPIPLIB */
6743 #endif /* UNIX */
6744 }
6745
6746 /*  N E T F L U I  --  Flush network input buffer  */
6747
6748 #ifdef TNCODE
6749 static int
6750 #ifdef CK_ANSIC
6751 netgetc(int timo)                       /* Input function to point to... */
6752 #else  /* CK_ANSIC */
6753 netgetc(timo) int timo;
6754 #endif /* CK_ANSIC */
6755 {                                       /* ...in the tn_doop() call */
6756 #ifdef TCPIPLIB
6757     return netinc(timo);
6758 #else /* TCPIPLIB */
6759     return ttinc(timo);
6760 #endif /* TCPIPLIB */
6761 }
6762 #endif /* TNCODE */
6763
6764 int
6765 netflui() {
6766     int n;
6767     int ch;
6768 #ifdef NETLEBUF
6769     ttpush = -1;                        /* Clear the peek-ahead char */
6770     while (le_data && (le_inbuf() > 0)) {
6771         CHAR ch = '\0';
6772         if (le_getchar(&ch) > 0) {
6773             debug(F101,"ttflui le_inbuf ch","",ch);
6774         }
6775     }
6776 #endif /* NETLEBUF */
6777
6778 #ifdef TCPIPLIB
6779 #ifdef OS2
6780     RequestTCPIPMutex(SEM_INDEFINITE_WAIT);
6781 #endif /* OS2 */
6782 #ifdef TNCODE
6783     if (ttnproto == NP_TELNET) {
6784         /* Netflui must process Telnet negotiations or get out of sync */
6785         if ((n = nettchk()) <= 0)
6786           goto exit_flui;
6787         while (n-- > 0) {
6788             ch = netinc(1);
6789             if (ch == IAC) {
6790                 extern int duplex;  /* this really shouldn't be here but ... */
6791                 int tx = tn_doop((CHAR)(ch & 0xff),duplex,netgetc);
6792                 if (tx == 1) duplex = 1;
6793                 else if (tx == 2) duplex = 0;
6794                 n = nettchk();
6795             }
6796         }
6797     } else
6798 #endif /* TNCODE */
6799     {
6800         ttibuf[ttibp+ttibn] = '\0';
6801         debug(F111,"netflui 1",ttibuf,ttibn);
6802 #ifdef CK_ENCRYPTION
6803         if (TELOPT_U(TELOPT_ENCRYPTION)) {
6804             ck_tn_decrypt(&ttibuf[ttibp],ttibn);
6805         }
6806 #endif /* CK_ENCRYPTION */
6807         ttibn = ttibp = 0;              /* Flush internal buffer *FIRST* */
6808         if (ttyfd < 1)
6809           goto exit_flui;
6810         if ((n = nettchk()) > 0) {      /* Now see what's waiting on the net */
6811             if (n > TTIBUFL) n = TTIBUFL;       /* and sponge it up */
6812             debug(F101,"netflui 2","",n);       /* ... */
6813             n = socket_read(ttyfd,ttibuf,n); /* into our buffer */
6814             if (n >= 0) ttibuf[n] = '\0';
6815             debug(F111,"netflui 3",ttibuf,n);
6816 #ifdef CK_ENCRYPTION
6817             if (TELOPT_U(TELOPT_ENCRYPTION)) {
6818                 ck_tn_decrypt(&ttibuf[ttibp],n);
6819             }
6820 #endif /* CK_ENCRYPTION */
6821             ttibuf[0] = '\0';
6822         }
6823     }
6824 #else  /* !TCPIPLIB */
6825     if (ttyfd < 1)
6826       goto exit_flui;
6827 #ifdef TNCODE
6828     if (ttnproto == NP_TELNET) {
6829         if ((n = ttchk()) <= 0)
6830           goto exit_flui;
6831         while (n-- >= 0) {
6832             /* Netflui must process Telnet negotiations or get out of sync */
6833             ch = ttinc(1);
6834             if (ch == IAC) {
6835                 extern int duplex;  /* this really shouldn't be here but ... */
6836                 int tx = tn_doop((CHAR)(ch & 0xff),duplex,netgetc);
6837                 if (tx == 1) duplex = 1;
6838                 else if (tx == 2) duplex = 0;
6839                 n = ttchk();
6840             }
6841         };
6842     } else
6843 #endif /* TNCODE */
6844     if ((n = ttchk()) > 0) {
6845         debug(F101,"netflui non-TCPIPLIB","",n);
6846         while ((n--) && ttinc(1) > -1)  /* Don't worry, ttinc() is buffered */
6847           ;                             /* and it handles the decryption... */
6848     }
6849 #endif /* TCPIPLIB */
6850   exit_flui:
6851 #ifdef OS2
6852     ReleaseTCPIPMutex();
6853 #endif /* OS2 */
6854     return(0);
6855 }
6856
6857 #ifdef CK_KERBEROS
6858 /* The following two functions are required for encrypted rlogin */
6859 /* They are called with nettoc() or nettol() are transmitting    */
6860 /* encrypted data.  They call a function to encrypt the data     */
6861 /* and that function needs to be able to write to/read from the  */
6862 /* network in an unimpeded manner.  Hence, these two simple fns. */
6863 int
6864 net_write(fd, buf, len)
6865     int fd;
6866     register const char *buf;
6867     int len;
6868 {
6869     int cc;
6870     register int wrlen = len;
6871     do {
6872 #ifdef TCPIPLIB
6873         cc = socket_write(fd, buf, wrlen);
6874 #else
6875         cc = write(fd,buf,wrlen);
6876 #endif /* TCPIPLIB */
6877         if (cc < 0) {
6878             int s_errno = socket_errno;
6879             debug(F101,"net_write error","",s_errno);
6880 #ifdef OS2
6881             if (os2socketerror(s_errno) < 0)
6882                 return(-1);
6883             else
6884                 continue;
6885 #else /* OS2 */
6886             if (errno == EINTR)
6887                 continue;
6888             return(-1);
6889 #endif /* OS2 */
6890         }
6891         else {
6892             buf += cc;
6893             wrlen -= cc;
6894         }
6895     } while (wrlen > 0);
6896     return(len);
6897 }
6898 int
6899 net_read(fd, buf, len)
6900     int fd;
6901     register char *buf;
6902     register int len;
6903 {
6904     int cc, len2 = 0;
6905
6906     do {
6907 #ifdef TCPIPLIB
6908         cc = socket_read(fd, buf, len);
6909 #else
6910         cc = read(fd,buf,len);
6911 #endif
6912         if (cc < 0) {
6913             int s_errno = socket_errno;
6914             debug(F101,"net_read error","",s_errno);
6915 #ifdef OS2
6916             if (os2socketerror(s_errno) < 0)
6917                 return(-1);
6918 #endif /* OS2 */
6919             return(cc);          /* errno is already set */
6920         }
6921         else if (cc == 0) {
6922             netclos();
6923             return(len2);
6924         } else {
6925             buf += cc;
6926             len2 += cc;
6927             len -= cc;
6928         }
6929     } while (len > 0);
6930     return(len2);
6931 }
6932 #endif /* CK_KERBEROS */
6933 #endif /* NONET */
6934
6935 /* getlocalipaddr() attempts to resolve an IP Address for the local machine.
6936  *   If the host is multi-homed it returns only one address.
6937  *
6938  * Two techniques are used.
6939  * (1) get the local host name and perform a DNS lookup, then take
6940  *     the first entry;
6941  * (2) open a UDP socket, use it to connect to a fictitious host (it's OK,
6942  *    no data is sent), then retrieve the local address from the socket.
6943  * Note: the second technique won't work on Microsoft systems.  See
6944  * Article ID: Q129065 PRB: Getsockname() Returns IP Address 0.0.0.0 for UDP
6945  */
6946
6947 /* Technique number one cannot work reliably if the machine is a laptop
6948  * and the hostname is associated with a physical adapter which is not
6949  * installed and a PPP connection is being used instead.  This is because
6950  * the hostname DNS lookup will succeed for the physical adapter even though
6951  * it would be impossible to use it.  In NT4 SP4, the gethostbyname()
6952  * when given the result of gethostname() returns not the real DNS entries
6953  * for that name+domain.  Instead it returns all of the static and dynamic
6954  * IP addresses assigned to any physical or virtual adapter defined in the
6955  * system regardless of whether or not it is installed.  The order of the
6956  * addresses is fixed according to the binding order in the NT registry.
6957  */
6958
6959 /*
6960  * It appears that calling gethostbyname(NULL) is more reliable than
6961  * calling gethostbyname(gethostname()) on Windows.  So on Windows we will
6962  * only call gethostbyname(NULL).
6963  */
6964
6965 int
6966 getlocalipaddr() {
6967 #ifndef datageneral
6968     struct sockaddr_in l_sa;
6969     struct sockaddr_in r_sa;
6970     GSOCKNAME_T slen = sizeof(struct sockaddr_in);
6971     int sock;
6972     int rc;
6973     struct in_addr laddr;
6974
6975     /* if still not resolved, then try second strategy */
6976     /* This second strategy does not work on Windows */
6977
6978     debug(F100,"getlocalipaddr","",0);
6979     memset(&l_sa,0,slen);
6980     memset(&r_sa,0,slen);
6981
6982     /* get a UDP socket */
6983     sock = socket(AF_INET, SOCK_DGRAM, 0);
6984     if (sock != -1) {
6985         /* connect to arbirary port and address (NOT loopback) */
6986         r_sa.sin_family = AF_INET;
6987         r_sa.sin_port = htons(IPPORT_ECHO);
6988
6989         /* The following is an "illegal conversion" in AOS/VS */
6990         /* (and who knows where else) */
6991
6992 #ifdef INADDRX
6993         inaddrx = inet_addr("128.127.50.1");
6994         r_sa.sin_addr.s_addr = *(unsigned long *)&inaddrx;
6995 #else
6996         r_sa.sin_addr.s_addr = inet_addr("128.127.50.1");
6997 #endif /* INADDRX */
6998         rc = connect(sock, (struct sockaddr *) &r_sa, sizeof(struct sockaddr));
6999         if (!rc) {                      /* get local address */
7000             getsockname(sock,(struct sockaddr *)&l_sa,&slen);
7001 #ifdef TCPIPLIB
7002             socket_close(sock);         /* We're done with the socket */
7003 #else
7004             close(sock);
7005 #endif /* TCPIPLIB */
7006             if (l_sa.sin_addr.s_addr != INADDR_ANY) {
7007                 myxipaddr = ntohl(l_sa.sin_addr.s_addr);
7008                 ckstrncpy(myipaddr,(char *)inet_ntoa(l_sa.sin_addr),20);
7009                 debug(F110,"getlocalipaddr setting buf to",myipaddr,0);
7010                 return(0);
7011             }
7012         }
7013     }
7014     return getlocalipaddrs(myipaddr,sizeof(myipaddr),0);
7015 #else /* datageneral */
7016     return(-1);
7017 #endif /* datageneral */
7018 }
7019
7020 int
7021 getlocalipaddrs(buf,bufsz,index)
7022     char * buf;
7023     int    bufsz;
7024     int    index;
7025 /* getlocalipaddrs */ {
7026 #ifndef datageneral
7027     char localhost[256];
7028     struct hostent * host=NULL;
7029     struct sockaddr_in l_sa;
7030     struct sockaddr_in r_sa;
7031     GSOCKNAME_T slen = sizeof(struct sockaddr_in);
7032     int rc;
7033 #ifdef COMMENT
7034     int sock;
7035     char messageBuf[60];
7036     struct in_addr laddr;
7037 #endif /* COMMENT */
7038
7039     debug(F100,"getlocalipaddrs","",0);
7040     memset(&l_sa,0,slen);
7041     memset(&r_sa,0,slen);
7042
7043     /* init local address (to zero) */
7044     l_sa.sin_addr.s_addr = INADDR_ANY;
7045
7046 #ifdef CKGHNLHOST
7047     rc = gethostname(localhost, 256);
7048     debug(F110,"getlocalipaddrs localhost",localhost,0);
7049 #else
7050     /* This doesn't work on some platforms, e.g. Solaris */
7051     rc = 0;
7052     localhost[0] = '\0';
7053 #ifdef NT
7054     if ( winsock_version < 20 ) {
7055         rc = gethostname(localhost, 256);
7056         debug(F110,"getlocalipaddrs localhost",localhost,0);
7057     }
7058 #endif /* NT */
7059 #endif /* CKGHNLHOST */
7060     if (!rc) {
7061         /* resolve host name for local address */
7062         debug(F110,"getlocalipaddrs","calling gethostbyname()",0);
7063         host = gethostbyname(localhost);
7064         /* debug(F111,"getlocalipaddrs","gethostbyname() returned",host); */
7065         if (host) {
7066 #ifdef HADDRLIST
7067             host = ck_copyhostent(host);
7068             if ( index < 0 || index > 63 || !host->h_addr_list[index] ) {
7069                 buf[0] = '\0';
7070                 return(-1);
7071             }
7072             l_sa.sin_addr.s_addr =
7073               *((unsigned long *) (host->h_addr_list[index]));
7074             ckstrncpy(buf,(char *)inet_ntoa(l_sa.sin_addr),20);
7075             debug(F110,"getlocalipaddrs setting buf to",buf,0);
7076
7077 #ifdef COMMENT
7078             /* This is for reporting multiple IP Address */
7079             while (host->h_addr_list && host->h_addr_list[0]) {
7080                 l_sa.sin_addr.s_addr =
7081                   *((unsigned long *) (host->h_addr_list[0]));
7082                 ckstrncpy(messageBuf,
7083                         (char *)inet_ntoa(l_sa.sin_addr),60);
7084                 if (tcp_address) {
7085                     if (!strcmp(messageBuf,tcp_address))
7086                       ckstrncpy(myipaddr,tcp_address,20);
7087                 }
7088                 debug(F110,"getlocalipaddrs ip address list", messageBuf, 0);
7089                 host->h_addr_list++;
7090             }
7091 #endif /* COMMENT */
7092 #else   /* HADDRLIST */
7093             if (index != 0) {
7094                 buf[0] = '\0';
7095                 return(-1);
7096             }
7097             l_sa.sin_addr.s_addr = *((unsigned long *) (host->h_addr));
7098             ckstrncpy(buf,(char *)inet_ntoa(l_sa.sin_addr),bufsz);
7099             debug(F110,"getlocalipaddrs setting buf to",buf,0);
7100 #endif  /* HADDRLIST */
7101             return(0);
7102         } else debug(F110,
7103                      "getlocalipaddrs: gethostbyname() failed",
7104                      localhost,
7105                      0
7106                      );
7107     }
7108 #endif /* datageneral */
7109     return(-1);
7110 }
7111
7112 #ifdef RLOGCODE                 /* TCP/IP RLOGIN protocol support code */
7113 int
7114 rlog_naws() {
7115     struct rlog_naws {
7116         unsigned char id[4];
7117         unsigned short rows, cols, ypix, xpix;
7118     } nawsbuf;
7119
7120     if (ttnet != NET_TCPB)
7121       return 0;
7122     if (ttnproto != NP_RLOGIN
7123 #ifdef CK_KERBEROS
7124         && ttnproto != NP_K4LOGIN
7125         && ttnproto != NP_EK4LOGIN
7126         && ttnproto != NP_K5LOGIN
7127         && ttnproto != NP_EK5LOGIN
7128 #endif /* CK_KERBEROS */
7129          )
7130       return 0;
7131     if (!TELOPT_ME(TELOPT_NAWS))
7132       return 0;
7133
7134     debug(F100,"rlogin Window Size sent","",0);
7135
7136     nawsbuf.id[0] = nawsbuf.id[1] = 0377;
7137     nawsbuf.id[2] = nawsbuf.id[3] = 's';
7138 #ifdef OS2
7139     nawsbuf.rows = htons((unsigned short) (VscrnGetHeight(VTERM)
7140                           -(tt_status[VTERM]?1:0)));
7141     nawsbuf.cols = htons((unsigned short) VscrnGetWidth(VTERM));
7142 #else /* OS2 */
7143     nawsbuf.rows = htons((unsigned short) tt_rows);
7144     nawsbuf.cols = htons((unsigned short) tt_cols);
7145 #endif /* OS2 */
7146     nawsbuf.ypix = htons(0);            /* y pixels */
7147
7148     nawsbuf.xpix = htons(0);            /* x pixels */
7149     if (ttol((CHAR *)(&nawsbuf), sizeof(nawsbuf)) < 0)
7150       return(-1);
7151     return(0);
7152 }
7153
7154 #ifdef OS2ORUNIX
7155 #define RLOGOUTBUF
7156 #endif /* OS2 */
7157 static int
7158 #ifdef CK_ANSIC
7159 rlog_ini(CHAR * hostname, int port,
7160          struct sockaddr_in * l_addr, struct sockaddr_in * r_addr)
7161 #else /* CK_ANSIC */
7162 rlog_ini(hostname, port, l_addr, r_addr)
7163     CHAR * hostname;
7164     int port;
7165     struct sockaddr_in * l_addr;
7166     struct sockaddr_in * r_addr;
7167 #endif /* CK_ANSIC */
7168 /* rlog_ini */ {
7169
7170 #ifdef RLOGOUTBUF
7171     char outbuf[512];
7172     int  outbytes=0;
7173 #endif /* RLOGOUTBUF */
7174     int flag = 0;
7175 #define TERMLEN 16
7176 #define CONSPDLEN 16
7177     CHAR localuser[UIDBUFLEN+1];
7178     CHAR remoteuser[UIDBUFLEN+1];
7179     int userlen = 0;
7180     CHAR term_speed[TERMLEN+CONSPDLEN+1];
7181 #ifdef CONGSPD
7182     long conspd = -1L;
7183 #endif /* CONGSPD */
7184 #ifdef OS2
7185     extern int tt_type, max_tt;
7186     extern struct tt_info_rec tt_info[];
7187 #endif /* OS2 */
7188     int i, n;
7189
7190     int rc = 0;
7191     tn_reset();                 /* This call will reset all of the Telnet */
7192                                 /* options and then quit.  We need to do  */
7193                                 /* this since we use the Telnet options   */
7194                                 /* to hold various state information      */
7195     duplex = 0;                 /* Rlogin is always remote echo */
7196     rlog_inband = 0;
7197
7198 #ifdef CK_TTGWSIZ
7199 /*
7200   But compute the values anyway before the first read since the out-
7201   of-band NAWS request would arrive before the first data byte (NULL).
7202 */
7203 #ifdef OS2
7204     /* Console terminal screen rows and columns */
7205     debug(F101,"rlog_ini tt_rows 1","",VscrnGetHeight(VTERM)
7206            -(tt_status[VTERM]?1:0));
7207     debug(F101,"rlog_ini tt_cols 1","",VscrnGetWidth(VTERM));
7208     /* Not known yet */
7209     if (VscrnGetWidth(VTERM) < 0 ||
7210         VscrnGetHeight(VTERM)-(tt_status[VTERM]?1:0) < 0) {
7211         ttgwsiz();                      /* Try to get screen dimensions */
7212     }
7213     debug(F101,
7214           "rlog_ini tt_rows 2",
7215           "",
7216           VscrnGetHeight(VTERM)-(tt_status[VTERM]?1:0)
7217           );
7218     debug(F101,"rlog_ini tt_cols 2","",VscrnGetWidth(VTERM));
7219 #else /* OS2 */
7220     debug(F101,"rlog_ini tt_rows 1","",tt_rows);
7221     debug(F101,"rlog_ini tt_cols 1","",tt_cols);
7222     if (tt_rows < 0 || tt_cols < 0) {   /* Not known yet */
7223         ttgwsiz();                      /* Try to find out */
7224     }
7225     debug(F101,"rlog_ini tt_rows 2","",tt_rows);
7226     debug(F101,"rlog_ini tt_cols 2","",tt_cols);
7227 #endif /* OS2 */
7228 #endif /* CK_TTGWSIZ */
7229
7230     ttflui();                           /* Start by flushing the buffers */
7231
7232     rlog_mode = RL_COOKED;
7233
7234     /* Determine the user's local username ... */
7235
7236     localuser[0] = '\0';
7237 #ifdef NT
7238     {
7239         char localuid[UIDBUFLEN+1];
7240         ckstrncpy((char *)localuser,(char *)GetLocalUser(),UIDBUFLEN);
7241     }
7242
7243     if ( !localuser[0] )
7244 #endif /* NT */
7245     {
7246         char * user = getenv("USER");
7247         if (!user)
7248           user = "";
7249         userlen = strlen(user);
7250         debug(F111,"rlogin getenv(USER)",user,userlen);
7251         ckstrncpy((char *)localuser,user,UIDBUFLEN);
7252         debug(F110,"rlog_ini localuser 1",localuser,0);
7253     }
7254     if ( !localuser[0] )
7255         strcpy((char *)localuser,"unknown");
7256     else if (ck_lcname) {
7257         cklower((char *)localuser);
7258         debug(F110,"rlog_ini localuser 2",localuser,0);
7259     }
7260
7261     /* And the username to login with */
7262     if (uidbuf[0]) {
7263         ckstrncpy((char *)remoteuser,uidbuf,UIDBUFLEN);
7264         debug(F110,"rlog_ini remoteuser 1",remoteuser,0);
7265     } else if (localuser[0]) {
7266         ckstrncpy((char *)remoteuser,(char *)localuser,UIDBUFLEN);
7267         debug(F110,"rlog_ini remoteuser 2",remoteuser,0);
7268     } else {
7269         remoteuser[0] = '\0';
7270         debug(F110,"rlog_ini remoteuser 3",remoteuser,0);
7271     }
7272     if (ck_lcname)
7273       cklower((char *)remoteuser);
7274     debug(F110,"rlog_ini remoteuser 4",remoteuser,0);
7275
7276     /* The command to issue is the terminal type and speed */
7277     term_speed[0] = '\0';
7278     if (tn_term) {                      /* SET TELNET TERMINAL-TYPE value */
7279         if (*tn_term) {                 /* (if any) takes precedence. */
7280             ckstrncpy((char *)term_speed, tn_term, TERMLEN);
7281             flag = 1;
7282         }
7283     } else {                            /* Otherwise the local terminal type */
7284 #ifdef OS2
7285         /* In terminal-emulating versions, it's the SET TERM TYPE value */
7286         ckstrncpy(term_speed, (tt_type >= 0 && tt_type <= max_tt) ?
7287                 tt_info[tt_type].x_name : "network", TERMLEN);
7288 #else
7289         /* In the others, we just look at the TERM environment variable */
7290         {
7291             char *p = getenv("TERM");
7292             if (p)
7293               ckstrncpy((char *)term_speed,p,TERMLEN);
7294             else
7295               term_speed[0] = '\0';
7296 #ifdef VMS
7297             for (p = (char *) term_speed; *p; p++) {
7298                 if (*p == '-' && (!strcmp(p,"-80") || !strcmp(p,"-132")))
7299                   break;
7300                 else if (isupper(*p))
7301                   *p = tolower(*p);
7302             }
7303             *p = '\0';
7304 #endif /* VMS */
7305         }
7306 #endif /* OS2 */
7307     }
7308     n = strlen((char *)term_speed);
7309     if (n > 0) {                        /* We have a terminal type */
7310         if (!flag) {                    /* If not user-specified */
7311             for (i = 0; i < n; i++)     /* then lowercase it.    */
7312               if (isupper(term_speed[i]))
7313                 term_speed[i] = tolower(term_speed[i]);
7314         }
7315         debug(F110,"rlog_ini term_speed 1",term_speed,0);
7316
7317 #ifdef CONGSPD
7318         /* conspd() is not yet defined in all ck*tio.c modules */
7319         conspd = congspd();
7320         if (conspd > 0L) {
7321             ckstrncat((char *)term_speed,"/",sizeof(term_speed));
7322             ckstrncat((char *)term_speed,ckltoa(conspd),sizeof(term_speed));
7323         } else
7324 #endif /* CONGSPD */
7325           ckstrncat((char *)term_speed,"/19200",sizeof(term_speed));
7326         debug(F110,"rlog_ini term_speed 2",term_speed,0);
7327     } else {
7328         term_speed[0] = '\0';
7329         debug(F110,"rlog_ini term_speed 3",term_speed,0);
7330     }
7331
7332 #ifdef CK_KERBEROS
7333     if (ttnproto == NP_K4LOGIN || ttnproto == NP_EK4LOGIN ||
7334         ttnproto == NP_K5LOGIN || ttnproto == NP_EK5LOGIN) {
7335         int kver, encrypt, rc;
7336         switch (ttnproto) {
7337           case NP_K4LOGIN:
7338             kver = 4;
7339             encrypt = 0;
7340             break;
7341           case NP_EK4LOGIN:
7342             kver = 4;
7343             encrypt = 1;
7344             break;
7345           case NP_K5LOGIN:
7346             kver = 5;
7347             encrypt = 0;
7348             break;
7349           case NP_EK5LOGIN:
7350             kver = 5;
7351             encrypt = 1;
7352             break;
7353         default:
7354             kver = 0;
7355             encrypt = 0;
7356         }
7357         rc = ck_krb_rlogin(hostname, port,
7358                            localuser, remoteuser, term_speed,
7359                            l_addr, r_addr, kver, encrypt);
7360         if (!rc) {                      /* success */
7361             TELOPT_ME(TELOPT_NAWS) = 1;
7362             rc = rlog_naws();
7363         }
7364         return(rc);
7365     } else
7366 #endif /* CK_KERBEROS */
7367     if (ttnproto == NP_RLOGIN) {
7368 #ifdef RLOGOUTBUF
7369         /*
7370          *  The rcmds start the connection with a series of init data:
7371          *
7372          *    a port number upon which client is listening for stderr data
7373          *    the user's name on the client machine
7374          *    the user's name on the server machine
7375          *    the terminal_type/speed or command to execute
7376          */
7377         outbuf[outbytes++] = 0;
7378         strcpy((char *)outbuf+outbytes,(char *)localuser);
7379         outbytes += strlen((char *)localuser) + 1;
7380         strcpy((char *)outbuf+outbytes,(char *)remoteuser);
7381         outbytes += strlen((char *)remoteuser) + 1;
7382         strcpy((char *)outbuf+outbytes,(char *)term_speed);
7383         outbytes += strlen((char *)term_speed) + 1;
7384         rc = ttol((CHAR *)outbuf,outbytes);
7385 #else /* RLOGOUTBUF */
7386         ttoc(0);                        /* Send an initial NUL as wake-up */
7387         /* Send each variable with the trailing NUL */
7388         rc = ttol(localuser,strlen((char *)localuser)+1);
7389         if (rc > 0)
7390           rc = ttol(remoteuser,strlen((char *)remoteuser)+1);
7391         if (rc > 0)
7392           rc = ttol(term_speed,strlen((char *)term_speed)+1);
7393 #endif /* RLOGOUTBUF */
7394
7395         /* Now we are supposed to get back a single NUL as confirmation */
7396         errno = 0;
7397         rc = ttinc(60);
7398         debug(F101,"rlogin first ttinc","",rc);
7399         if (rc > 0) {
7400             debug(F101,"rlogin ttinc 1","",rc);
7401             printf(
7402                "Rlogin protocol error - 0x%x received instead of 0x00\n", rc);
7403             return(-1);
7404         } else if (rc < 0) {
7405             debug(F101,"rlogin ttinc errno","",errno);
7406             /* printf("Network error: %d\n", errno); */
7407             return(-1);
7408         }
7409     }
7410     return(0);
7411 }
7412
7413 /* two control messages are defined:
7414
7415    a double flag byte of 'o' indicates a one-byte message which is
7416    identical to what was once carried out of band.
7417
7418    a double flag byte of 'q' indicates a zero-byte message.  This
7419    message is interpreted as two \377 data bytes.  This is just a
7420    quote rule so that binary data from the server does not confuse the
7421    client.  */
7422
7423 int 
7424 rlog_ctrl(cp, n)
7425      unsigned char *cp;
7426      int n;
7427 {
7428     if ((n >= 5) && (cp[2] == 'o') && (cp[3] == 'o')) {
7429         if (rlog_oob(&cp[4],1))
7430             return(-5);
7431         return(5);
7432     } else if ((n >= 4) && (cp[2] == 'q') && (cp[3] == 'q')) {
7433         /* this is somewhat of a hack */
7434         cp[2] = '\377';
7435         cp[3] = '\377';
7436         return(2);
7437     }
7438     return(0);
7439 }
7440
7441 static int
7442 rlog_oob(oobdata, count) CHAR * oobdata; int count; {
7443     int i;
7444     int flush = 0;
7445
7446     debug(F111,"rlogin out_of_band","count",count);
7447
7448     for (i = 0; i<count; i++)   {
7449         debug(F101,"rlogin out_of_band","",oobdata[i]);
7450                 if (oobdata[i] & 0x01)
7451                         continue;
7452
7453         if (oobdata[i] & 0x02) { /* Flush Buffered Data not yet displayed */
7454             debug(F101,"rlogin Flush Buffered Data command","",oobdata[i]);
7455
7456             /* Only flush the data if in fact we are in a mode that won't */
7457             /* get out of sync.  Ie, not when we are in protocol mode.    */
7458             switch ( what ) {
7459             case W_NOTHING:
7460             case W_CONNECT:
7461             case W_COMMAND:
7462                 if ( rlog_inband )
7463                     flush = 1;
7464                 else
7465                     ttflui();
7466                 break;
7467             }
7468         }
7469         if (oobdata[i] & 0x10) {        /* Switch to RAW mode */
7470             debug(F101,"rlogin Raw Mode command","",oobdata[i]);
7471             rlog_mode = RL_RAW;
7472         }
7473
7474         if (oobdata[i] & 0x20) {        /* Switch to COOKED mode */
7475             debug(F101,"rlogin Cooked Mode command","",oobdata[i]);
7476             rlog_mode = RL_COOKED;
7477         }
7478         if (oobdata[i] & 0x80)
7479         {        /* Send Window Size Info */
7480             debug(F101,"rlogin Window Size command","",oobdata[i]);
7481             /* Remember to send WS Info when Window Size changes */
7482             if ( !TELOPT_ME(TELOPT_NAWS) ) {
7483                 TELOPT_ME(TELOPT_NAWS) = 1;
7484                 rlog_naws();
7485             }
7486         }
7487     }
7488     return(flush);
7489 }
7490 #ifndef TCPIPLIB
7491 static SIGTYP
7492 rlogoobh(sig) int sig; {
7493 #ifdef SOLARIS
7494     char                                /* Or should it be char for all? */
7495 #else
7496     CHAR
7497 #endif /* SOLARIS */
7498       oobdata;
7499
7500     /* int  count = 0; */ /* (not used) */
7501
7502     while (recv(ttyfd, &oobdata, 1, MSG_OOB) < 0) {
7503       /*
7504        * We need to do some special processing here.
7505        * Just in case the socket is blocked for input
7506        *
7507        */
7508         switch (errno) {
7509           case EWOULDBLOCK:
7510             break;
7511           default:
7512             return;
7513         }
7514     }
7515     debug(F101,"rlogin out_of_band","",oobdata);
7516     if (oobdata == 0x02) {      /* Flush Buffered Data not yet displayed */
7517         debug(F101,"rlogin Flush Buffered Data command","",oobdata);
7518         netflui();
7519     }
7520     if (oobdata & 0x10) {               /* Switch to raw mode */
7521         debug(F101,"rlogin Raw Mode command","",oobdata);
7522         rlog_mode = RL_RAW;
7523     }
7524     if (oobdata & 0x20) {               /* Switch to cooked mode */
7525         debug(F101,"rlogin Cooked Mode command","",oobdata);
7526         rlog_mode = RL_COOKED;
7527     }
7528     if (oobdata & 0x80) {                 /* Send Window Size Info */
7529         debug(F101,"rlogin Window Size command","",oobdata);
7530         /* Remember to send WS Info when Window Size changes */
7531         if ( !TELOPT_ME(TELOPT_NAWS) ) {
7532             TELOPT_ME(TELOPT_NAWS) = 1;
7533             rlog_naws();
7534         }
7535     }
7536 }
7537 #endif /* TCPIPLIB */
7538 #endif /* RLOGCODE */
7539
7540 /* Send network BREAK */
7541 /*
7542   Returns -1 on error, 0 if nothing happens, 1 if BREAK sent successfully.
7543 */
7544 int
7545 netbreak() {
7546     CHAR buf[3];
7547     if (ttnet == NET_TCPB) {
7548         if (ttnproto == NP_TELNET) {
7549 #ifdef TNCODE
7550             buf[0] = (CHAR) IAC; buf[1] = (CHAR) BREAK; buf[2] = (CHAR) 0;
7551             if (
7552 #ifdef OS2
7553                 nettol((char *) buf, 2)
7554 #else
7555                 ttol(buf, 2)
7556 #endif /* OS2 */
7557                 < 2)
7558               return(-1);
7559             if (tn_deb || debses || deblog) {
7560                 extern char tn_msg[];
7561                 ckmakmsg(tn_msg,TN_MSG_LEN,"TELNET SENT ",TELCMD(BREAK),
7562                           NULL,NULL);
7563                 debug(F101,tn_msg,"",BREAK);
7564                 if (debses || tn_deb) tn_debug(tn_msg);
7565             }
7566             return(1);
7567 #else
7568             debug(F100,"netbreak no TNCODE","",0);
7569             return(0);
7570 #endif /* TNCODE */
7571         }
7572         /* Insert other TCP/IP protocols here */
7573     }
7574     /* Insert other networks here */
7575     return(0);
7576 }
7577 #endif /* NETCONN */
7578
7579
7580 #ifdef NETCONN
7581 #ifdef SUNX25
7582 /*
7583   SunLink X.25 support by Marcello Frutig, Catholic University,
7584   Rio de Janeiro, Brazil, 1990.
7585 */
7586
7587 /* PAD X.3, X.28 and X.29 support */
7588
7589 static CHAR x29err[MAXPADPARMS+3] = { X29_ERROR, INVALID_PAD_PARM, '\0' };
7590
7591 /* Initialize PAD */
7592
7593 extern CHAR padparms[];
7594
7595 VOID
7596 initpad() {
7597   padparms[PAD_BREAK_CHARACTER]        = 0;  /* Break character */
7598   padparms[PAD_ESCAPE]                 = 1;  /* Escape permitted */
7599   padparms[PAD_ECHO]                   = 1;  /* Kermit PAD does echo */
7600   padparms[PAD_DATA_FORWARD_CHAR]      = 2;  /* forward character CR */
7601   padparms[PAD_DATA_FORWARD_TIMEOUT]   = 0;  /* no timeout forward condition */
7602   padparms[PAD_FLOW_CONTROL_BY_PAD]    = 0;  /* not used */
7603   padparms[PAD_SUPPRESSION_OF_SIGNALS] = 1;  /* allow PAD service signals */
7604   padparms[PAD_BREAK_ACTION]           = 21; /* brk action: INT pk + brk ind*/
7605   padparms[PAD_SUPPRESSION_OF_DATA]    = 0;  /* no supression of user data */
7606   padparms[PAD_PADDING_AFTER_CR]       = 0;  /* no padding after CR */
7607   padparms[PAD_LINE_FOLDING]           = 0;  /* no line fold */
7608   padparms[PAD_LINE_SPEED]             = 0;  /* line speed - don't care */
7609   padparms[PAD_FLOW_CONTROL_BY_USER]   = 0;  /* flow cont of PAD - not used */
7610   padparms[PAD_LF_AFTER_CR]            = 0;  /* no LF insertion after CR */
7611   padparms[PAD_PADDING_AFTER_LF]       = 0;  /* no padding after LF */
7612   padparms[PAD_EDITING]                = 1;  /* can edit */
7613   padparms[PAD_CHAR_DELETE_CHAR]       = 8;  /* character delete character */
7614   padparms[PAD_BUFFER_DELETE_CHAR]     = 21; /* buffer delete character */
7615   padparms[PAD_BUFFER_DISPLAY_CHAR]    = 18; /* buffer display character */
7616 }
7617
7618 /* Set PAD parameters */
7619
7620 VOID
7621 setpad(s,n) CHAR *s; int n; {
7622     int i;
7623     CHAR *ps = s;
7624
7625     if (n < 1) {
7626         initpad();
7627     } else {
7628         for (i = 0; i < n; i++) {
7629             if (*ps > MAXPADPARMS)
7630               x29err[i+2] = *ps;
7631             else
7632               padparms[*ps] = *(ps+1);
7633             ps += 2;
7634         }
7635     }
7636 }
7637
7638 /* Read PAD parameters */
7639
7640 VOID
7641 readpad(s,n,r) CHAR *s; int n; CHAR *r; {
7642     int i;
7643     CHAR *ps = s;
7644     CHAR *pr = r;
7645
7646     *pr++ = X29_PARAMETER_INDICATION;
7647     if (n > 0) {
7648         for (i = 0; i < n; i++, ps++) {
7649             if (*ps > MAXPADPARMS) {
7650                 x29err[i+2] = *ps++;
7651             } else {
7652                 *pr++ = *ps;
7653                 *pr++ = padparms[*ps++];
7654             }
7655         }
7656     } else {
7657         for (i = 1; i < MAXPADPARMS; i++) {
7658             *pr++ = i;
7659             *pr++ = padparms[i];
7660         }
7661     }
7662 }
7663
7664 int
7665 qbitpkt(s,n) CHAR *s; int n; {
7666     CHAR *ps = s;
7667     int x29cmd = *ps;
7668     CHAR *psa = s+1;
7669     CHAR x29resp[(MAXPADPARMS*2)+1];
7670
7671     switch (x29cmd) {
7672
7673         case X29_SET_PARMS:
7674             setpad (ps+1,n/2);
7675             if ((int)strlen((char *)x29err) > 2) {
7676                 ttol(x29err,(int)strlen((char *)x29err));
7677                 x29err[2] = '\0';
7678             }
7679             return (-2);
7680         case X29_READ_PARMS:
7681             readpad (ps+1,n/2,x29resp);
7682             setqbit ();
7683             ttol(x29resp,(n>1)?(n+1):(2*MAXPADPARMS+1));
7684             if ((int)strlen((char *)x29err) > 2) {
7685                 ttol(x29err,(int)strlen((char *)x29err));
7686                 x29err[2] = '\0';
7687             }
7688             resetqbit();
7689             break;
7690         case X29_SET_AND_READ_PARMS:
7691             setpad (ps+1,n/2);
7692             readpad (ps+1,n/2,x29resp);
7693             setqbit();
7694             ttol(x29resp,(n>1)?(n+1):(2*MAXPADPARMS+1));
7695             if ((int)strlen((char *)x29err) > 2) {
7696                 ttol (x29err,(int)strlen((char *)x29err));
7697                 x29err [2] = '\0';
7698             }
7699             resetqbit();
7700             return (-2);
7701         case X29_INVITATION_TO_CLEAR:
7702             (VOID) x25clear();
7703             return (-1);
7704         case X29_INDICATION_OF_BREAK:
7705             break;
7706     }
7707     return (0);
7708 }
7709
7710 /* PAD break action processor */
7711
7712 VOID
7713 breakact() {
7714     extern char x25obuf[MAXOX25];
7715     extern int obufl;
7716     extern int active;
7717     extern unsigned char tosend;
7718     static CHAR indbrk[3] = {
7719         X29_INDICATION_OF_BREAK,
7720         PAD_SUPPRESSION_OF_DATA,
7721         1
7722     };
7723     CHAR intudat, cause, diag;
7724
7725     if (x25stat() < 0) return;  /* Ignore if no virtual call established */
7726
7727     if (padparms[PAD_BREAK_ACTION] != 0) /* Forward condition */
7728         if (ttol((CHAR *)x25obuf,obufl) < 0) {
7729             perror ("\r\nCan't send characters");
7730             active = 0;
7731         } else {
7732             bzero (x25obuf,sizeof(x25obuf));
7733             obufl = 0;
7734             tosend = 0;
7735         };
7736
7737     switch (padparms[PAD_BREAK_ACTION]) {
7738
7739        case 0 : break;                  /* do nothing */
7740        case 1 : /* send interrupt packet with interrupt user data field = 1 */
7741                 intudat = 1;
7742                 x25intr (intudat);
7743                 break;
7744        case 2 : /* send reset packet with cause and diag = 0 */
7745                 cause = diag = 0;
7746                 x25reset (cause,diag);
7747                 break;
7748        case 5 : /* send interrupt packet with interrupt user data field = 0 */
7749                 intudat = 0;
7750                 x25intr (intudat);
7751                 setqbit ();
7752                 /* send indication of break without a parameter field */
7753                 ttoc(X29_INDICATION_OF_BREAK);
7754                 resetqbit ();
7755                 break;
7756        case 8 : active = 0;             /* leave data transfer */
7757                 conol ("\r\n");
7758                 break;
7759        case 21: /* send interrupt packet with interrupt user data field = 0 */
7760                 intudat = 0;
7761                 x25intr (intudat);
7762                 setpad (indbrk+1,2);    /* set pad to discard input */
7763                 setqbit ();
7764                 /* send indication of break with parameter field */
7765                 ttol (indbrk,sizeof(indbrk));
7766                 resetqbit ();
7767                 break;
7768      }
7769 }
7770
7771 /* X.25 support functions */
7772
7773 X25_CAUSE_DIAG diag;
7774
7775 /*
7776   Convert a null-terminated string representing an X.121 address
7777   to a packed BCD form.
7778 */
7779 int
7780 pkx121(str,bcd) char *str; CHAR *bcd; {
7781     int i, j;
7782     u_char c;
7783
7784     i = j = 0;
7785     while (str[i]) {
7786         if (i >= 15 || str [i] < '0' || str [i] > '9')
7787           return (-1);
7788         c = str [i] - '0';
7789         if (i & 1)
7790           bcd [j++] |= c;
7791         else
7792           bcd [j] = c << 4;
7793         i++;
7794     }
7795     return (i);
7796 }
7797
7798 /* Reads and prints X.25 diagnostic */
7799
7800 int
7801 x25diag () {
7802     int i;
7803
7804     bzero ((char *)&diag,sizeof(diag));
7805     if (ioctl(ttyfd,X25_RD_CAUSE_DIAG,&diag)) {
7806         perror ("Reading X.25 diagnostic");
7807         return(-1);
7808     }
7809     if (diag.datalen > 0) {
7810         printf ("X.25 Diagnostic :");
7811         for (i = 0; i < (int)diag.datalen; i++)
7812           printf(" %02h",diag.data[i])+
7813         printf ("\r\n");
7814     }
7815     return(0);
7816 }
7817
7818 /* X.25 Out-of-Band Signal Handler */
7819
7820 SIGTYP
7821 x25oobh(foo) int foo; {
7822     int oobtype;
7823     u_char oobdata;
7824     int t;
7825
7826     (VOID) signal(SIGURG,x25oobh);
7827     do {
7828         if (ioctl(ttyfd,X25_OOB_TYPE,&oobtype)) {
7829             perror ("Getting signal type");
7830             return;
7831         }
7832         switch (oobtype) {
7833           case INT_DATA:
7834             if (recv(ttyfd,(char *)&oobdata,1,MSG_OOB) < 0) {
7835                 perror ("Receiving X.25 interrupt data");
7836                 return;
7837             }
7838             t = oobdata;
7839             printf ("\r\nInterrupt received, data = %d\r\n", t);
7840             break;
7841           case VC_RESET:
7842             printf ("\r\nVirtual circuit reset\r\n");
7843             x25diag ();
7844             break;
7845           case N_RESETS:
7846             printf ("\r\nReset timeout\r\n");
7847             break;
7848           case N_CLEARS:
7849             printf ("\r\nClear timeout\r\n");
7850             break;
7851           case MSG_TOO_LONG:
7852             printf ("\r\nMessage discarded, too long\r\n");
7853             break;
7854           default:
7855             if (oobtype) printf("\r\nUnknown oob type %d\r\n",oobtype);
7856             break;
7857         }
7858     } while (oobtype);
7859 }
7860
7861 /* Send a X.25 interrupt packet */
7862
7863 int
7864 #ifdef CK_ANSIC
7865 x25intr(char intr)
7866 #else
7867 x25intr(intr) char intr;
7868 #endif /* CK_ANSIC */
7869 /* x25intr */ {
7870     if (send(ttyfd,&intr,1,MSG_OOB) < 0) return(-1);
7871     debug(F100,"X.25 intr","",0);
7872     return(0);
7873 }
7874
7875 /* Reset X.25 virtual circuit */
7876 int
7877 #ifdef CK_ANSIC
7878 x25reset(char cause, char diagn)
7879 #else
7880 x25reset(cause, diagn) char cause; char diagn;
7881 #endif /* CK_ANSIC */
7882 /* x25reset */ {
7883     bzero ((char *)&diag,sizeof(diag));
7884     diag.flags   = 0;
7885     diag.datalen = 2;
7886     diag.data[0] = cause;
7887     diag.data[1] = diagn;
7888     if (ioctl(ttyfd,X25_WR_CAUSE_DIAG,&diag) < 0)
7889       return(-1);
7890     debug(F100,"X.25 reset","",0);
7891     return(0);
7892 }
7893
7894 /* Clear X.25 virtual circuit */
7895 int
7896 x25clear() {
7897     int i;
7898     debug(F100,"X.25 clear","",0);
7899     bzero ((char *)&diag,sizeof(diag));
7900     diag.flags = (1 << DIAG_TYPE);
7901     diag.datalen = 2;
7902     diag.data[0] = 0;
7903     diag.data[1] = 0;
7904     ioctl (ttyfd,X25_WR_CAUSE_DIAG,&diag); /* Send Clear Request */
7905     return(ttclos(0));                  /* Close socket */
7906 }
7907
7908 /* X.25 status */
7909 int
7910 x25stat() {
7911     if (ttyfd == -1) return (-1);
7912     return(0);
7913 }
7914
7915 /* Set Q_BIT on */
7916 VOID
7917 setqbit() {
7918     static int qbiton = 1 << Q_BIT;
7919     ioctl (ttyfd,X25_SEND_TYPE,&qbiton);
7920 }
7921
7922 /* Set Q_BIT off */
7923 VOID
7924 resetqbit() {
7925     static int qbitoff = 0;
7926     ioctl (ttyfd,X25_SEND_TYPE,&qbitoff);
7927 }
7928
7929 /* Read n characters from X.25 circuit into buf */
7930
7931 int
7932 x25xin(n,buf) int n; CHAR *buf; {
7933     register int x, c;
7934     int qpkt;
7935
7936     do {
7937         x = read(ttyfd,buf,n);
7938         if (buf[0] & (1 << Q_BIT)) { /* If Q_BIT packet, process it */
7939             /* If return -1 : invitation to clear; -2 : PAD changes */
7940             if ((c=qbitpkt(buf+1,x-2)) < 0) return(c);
7941             qpkt = 1;
7942         } else qpkt = 0;
7943     } while (qpkt);
7944
7945 #ifdef COMMENT                  /* Disabled by Stephen Riehm 19.12.97 */
7946     /* BUG!
7947      * if buf[] is full, then this null lands in nirvana!
7948      * I was unable to find any code which needs a trailing null in buf[]
7949      */
7950     if (x > 0) buf[x] = '\0';
7951 #endif /* COMMENT */
7952     if (x < 1) x = -1;
7953     debug(F101,"x25xin x","",x);
7954
7955     return(x);
7956 }
7957
7958 #ifdef COMMENT /* NO LONGER NEEDED! */
7959 /* X.25 read a line */
7960
7961 int
7962 #ifdef PARSENSE
7963 #ifdef CK_ANSIC
7964 x25inl(CHAR *dest, int max,int timo, CHAR eol, CHAR start)
7965 #else
7966 x25inl(dest,max,timo,eol,start) int max,timo; CHAR *dest, eol, start;
7967 #endif /* CK_ANSIC */
7968 #else /* not PARSENSE */
7969 #ifdef CK_ANSIC
7970 x25inl(CHAR *dest, int max,int timo, CHAR eol)
7971 #else
7972 x25inl(dest,max,timo,eol) int max,timo; CHAR *dest, eol;
7973 #endif /* __SDTC__ */
7974 #endif /*PARSENSE */
7975  /* x25inl */ {
7976     CHAR *pdest;
7977     int pktype, goteol, rest, n;
7978     int i, flag = 0;
7979     extern int ttprty, ttpflg;
7980     int ttpmsk;
7981
7982     ttpmsk = (ttprty) ? 0177 : 0377;    /* Set parity stripping mask */
7983
7984     debug(F101,"x25inl max","",max);
7985     debug(F101,"x25inl eol","",eol);
7986     pdest  = dest;
7987     rest   = max;
7988     goteol = 0;
7989     do {
7990         n = read(ttyfd,pdest,rest);
7991         n--;
7992         pktype = *pdest & 0x7f;
7993         switch (pktype) {
7994           case 1 << Q_BIT:
7995             if (qbitpkt(pdest+1,--n) < 0) return(-2);
7996             break;
7997           default:
7998             if (flag == 0) { /* if not in packet, search start */
7999                 for (i = 1; (i < n) &&
8000                      !(flag = ((dest[i] & 0x7f) == start));
8001                      i++);
8002                 if (flag == 0) { /* not found, discard junk */
8003                     debug(F101,"x25inl skipping","",n);
8004                     continue;
8005                 } else {                /* found, discard junk before start */
8006                     int k;
8007                     n = n - i + 1;
8008                     for (k = 1; k <= n; k++, i++) dest[k] = dest[i];
8009                 }
8010             }
8011             for (i = 0; (i < n) && /* search for eol */
8012                  !(goteol=(((*pdest = *(pdest+1)&ttpmsk)&0x7f)== eol));
8013                  i++,pdest++);
8014             *pdest = '\0';
8015             rest -= n;
8016         }
8017     } while ((rest > 0) && (!goteol));
8018
8019     if (goteol) {
8020         n = max - rest;
8021         debug (F111,"x25inl X.25 got",(char *) dest,n);
8022         if (timo) ttimoff();
8023         if (ttpflg++ == 0 && ttprty == 0) {
8024             if ((ttprty = parchk(dest,start,n)) > 0) {
8025                 int j;
8026                 debug(F101,"x25inl senses parity","",ttprty);
8027                 debug(F110,"x25inl packet before",(char *)dest,0);
8028                 ttpmsk = 0x7f;
8029                 for (j = 0; j < n; j++)
8030                   dest[j] &= 0x7f; /* Strip parity from packet */
8031                 debug(F110,"x25inl packet after ",dest,0);
8032             } else {
8033                 debug(F101,"parchk","",ttprty);
8034                 if (ttprty < 0) { ttprty = 0; n = -1; }
8035             }
8036         }
8037         ttimoff();
8038         return(n);
8039     }
8040     ttimoff();
8041     return(-1);
8042 }
8043 #endif /* COMMENT */
8044 #endif /* SUNX25 */
8045
8046 #ifdef IBMX25
8047 /*
8048  * IBM X25 support - using the NPI streams interface
8049  * written by Stephen Riehm, pc-plus, Munich Germany
8050  */
8051
8052 /* riehm: missing functions / TODO list */
8053
8054 /*
8055   x25intr() - Send an interrupt packet
8056 */
8057
8058 /* return an error message depending on packet type */
8059 char *
8060 x25err(n) int n; {
8061     static char buf[30];
8062     switch (n) {
8063       case NBADADDR:     return "invalid address";
8064       case NBADOPT:      return "invalid options";
8065       case NACCESS:      return "no permission";
8066       case NNOADDR:      return "unable to allocate address";
8067       case NOUTSTATE:    return "invalid state";
8068       case NBADSEQ:      return "invalid sequence number";
8069       case NSYSERR:      return "system error";
8070       case NBADDATA:     return "invalid data size";
8071       case NBADFLAG:     return "invalid flag";
8072       case NNOTSUPPORT:  return "unsupported primitive";
8073       case NBOUND:       return "address in use";
8074       case NBADQOSPARAM: return "bad QOS parameters";
8075       case NBADQOSTYPE:  return "bad QOS type";
8076       case NBADTOKEN:    return "bad token value";
8077       case NNOPROTOID:   return "protocol id could not be allocated";
8078       case NODDCUD:      return "odd length call user data";
8079       default:
8080         ckmakmsg(buf,sizeof(buf),"Unknown NPI error ",ckitoa(n),NULL,NULL);
8081         return buf;
8082     }
8083 }
8084
8085 /* turn a meaningless primitive number into a meaningful primitive name */
8086 char *
8087 x25prim(n) int n; {
8088     static char buf[30];
8089     switch(n) {
8090       case N_BIND_ACK:     return "N_BIND_ACK";
8091       case N_BIND_REQ:     return "N_BIND_REQ";
8092       case N_CONN_CON:     return "N_CONN_CON";
8093       case N_CONN_IND:     return "N_CONN_IND";
8094       case N_CONN_REQ:     return "N_CONN_REQ";
8095       case N_CONN_RES:     return "N_CONN_RES";
8096       case N_DATACK_IND:   return "N_DATAACK_IND";
8097       case N_DATACK_REQ:   return "N_DATAACK_REQ";
8098       case N_DATA_IND:     return "N_DATA_IND";
8099       case N_DATA_REQ:     return "N_DATA_REQ";
8100       case N_DISCON_IND:   return "N_DISCON_IND";
8101       case N_DISCON_REQ:   return "N_DISCON_REQ";
8102       case N_ERROR_ACK:    return "N_ERROR_ACK";
8103       case N_EXDATA_IND:   return "N_EXDATA_IND";
8104       case N_EXDATA_REQ:   return "N_EXDATA_REQ";
8105       case N_INFO_ACK:     return "N_INFO_ACK";
8106       case N_INFO_REQ:     return "N_INFO_REQ";
8107       case N_OK_ACK:       return "N_OK_ACK";
8108       case N_OPTMGMT_REQ:  return "N_OPTMGMT_REQ";
8109       case N_RESET_CON:    return "N_RESET_CON";
8110       case N_RESET_IND:    return "N_RESET_IND";
8111       case N_RESET_REQ:    return "N_RESET_REQ";
8112       case N_RESET_RES:    return "N_RESET_RES";
8113       case N_UDERROR_IND:  return "N_UDERROR_IND";
8114       case N_UNBIND_REQ:   return "N_UNBIND_REQ";
8115       case N_UNITDATA_REQ: return "N_UNITDATA_REQ";
8116       case N_UNITDATA_IND: return "N_UNITDATA_IND";
8117       default:
8118         ckmakmsg(buf,sizeof(buf),"UNKNOWN (",ckitoa(n),")",NULL);
8119         return buf;
8120     }
8121 }
8122
8123 /*****************************************************************************
8124  * Function: x25getmsg()
8125  * Description: get a STREAMS message, and check it for errors
8126  *
8127  * Parameters:
8128  * fd           - file descriptor to x25 device (opened)
8129  * control      - control buffer (pre-allocated)
8130  * ctl_size     - size of control buffer
8131  * data         - data buffer (pre-allocated)
8132  * data_size    - size of data buffer
8133  * flags        - flags for getmsg()
8134  * expected     - expected Primitive type
8135  *
8136  * Return Value:
8137  *      >= 0    OK (size of data returned)
8138  *      -1      error
8139  *
8140  */
8141 int
8142 x25getmsg( fd, control, ctl_size, data, data_size, get_flags, expected )
8143     int                 fd;             /* X25 device (opened) */
8144     N_npi_ctl_t         *control;       /* control buffer (pre-allocated) */
8145     int                 ctl_size;       /* size of control buffer */
8146     N_npi_data_t        *data;          /* data buffer (pre-allocated) */
8147     int                 data_size;      /* size of data buffer */
8148     int                 *get_flags;     /* getmsg() flags */
8149     int                 expected;       /* expected primitive type */
8150 /* x25getmsg */ {
8151     int                 rc = 0;         /* return code */
8152     struct strbuf       *get_ctl=NULL;  /* getmsg control */
8153     struct strbuf       *get_data=NULL; /* getmsg data */
8154     int                 more = 0;       /* flag for more data etc */
8155     int                 file_status = -1; /* file async status */
8156     N_npi_ctl_t         * result;       /* pointer to simplify switch() */
8157     int                 packet_type = -1; /* unknown packet thus far */
8158
8159 #ifdef TRACE
8160     printf( "TRACE: entering x25getmsg\n" );
8161 #endif /* TRACE */
8162
8163     debug( F110, "x25getmsg waiting for packet ", x25prim( expected ), 0);
8164     /* prepare the control structures for getmsg */
8165     if (control) {
8166         if ((get_ctl = (struct strbuf*)malloc(sizeof(struct strbuf))) == NULL)
8167           {
8168               perror("kermit x25getmsg(): get_ctl malloc failed\n");
8169               debug( F100, "x25getmsg malloc failed for get_ctl\n", "", 0);
8170               return(-1);
8171           }
8172         /* allow getmsg to return an unexpected packet type (which may be
8173          * larger than the expected one)
8174          */
8175         get_ctl->maxlen = NPI_MAX_CTL;
8176         get_ctl->len = 0;
8177         get_ctl->buf = (char *)control;
8178     } else {
8179         printf(
8180  "kermit x25getmsg(): internal error. control buffer MUST be pre-allocated!\n"
8181                );
8182         debug(F100,"x25getmsg internal error. no buffer pre-allocated","",0);
8183         return( -1 );
8184     }
8185     if (data) {
8186         if ((get_data = (struct strbuf*)malloc(sizeof(struct strbuf))) == NULL)
8187           {
8188             perror("kermit x25getmsg(): get_data malloc failed\n");
8189             debug( F100, "x25getmsg malloc failed for get_data\n", "", 0);
8190             return(-1);
8191         }
8192         get_data->maxlen = (NPI_MAX_DATA < data_size ) ?
8193           NPI_MAX_DATA :
8194             data_size;
8195         get_data->len = 0;
8196         get_data->buf = (char *)data;
8197     }
8198
8199     /* get an X.25 packet -
8200      * it may be any kind of packet, so check for special cases
8201      * it may be split into multiple parts - so loop if necessary
8202      */
8203     do {
8204 #ifdef DEBUG
8205         printf( "kermit: x25getmsg(): getting a message\n" );
8206 #endif /* DEBUG */
8207         errno = 0;
8208         if ((more = getmsg(fd, get_ctl, get_data, get_flags)) < 0) {
8209 #ifdef DEBUG
8210             printf( "kermit: x25getmsg(): getmsg returned an error\n" );
8211             perror( "getmsg error was" );
8212 #endif /* DEBUG */
8213             debug(F101, "x25getmsg getmsg returned an error\n", "", errno);
8214             if ((errno == EAGAIN) && (get_data && (get_data->len > 0)) ) {
8215                 /* was in non-blocking mode, nothing to get, but we're
8216                  * already waiting for the rest of the packet -
8217                  * switch to blocking mode for the next read.
8218                  * file_status used to reset file status before returning
8219                  */
8220                 if ((file_status = fcntl(fd, F_GETFL, 0)) < 0
8221                     || fcntl(fd, F_SETFL, file_status & ~O_NDELAY) < 0)
8222                   {
8223                       perror("x25getmsg(): couldn't change x25 blocking mode");
8224                       debug(F101,
8225                             "x25getmsg fcntl returned an error\n", "", errno);
8226                       /* netclos(); */
8227                       rc = -1;
8228                       break;
8229                   } else {
8230                       /* loop again into a blocking getmsg() */
8231                       continue;
8232                   }
8233             } else {
8234                 /* no data to get in non-blocking mode - return empty handed */
8235                 perror( "x25getmsg(): getmsg failed" );
8236                 debug(F101,"x25getmsg getmsg returned an error\n", "", errno);
8237                 rc = -1;
8238                 break;
8239             }
8240         } else if (more & MORECTL) {
8241             /* panic - the control information was larger than the
8242              * maximum control buffer size!
8243              */
8244             /* riehm: close connection? */
8245 #ifdef DEBUG
8246             printf("x25getmsg(): received partial control packet - panic\n");
8247 #endif /* DEBUG */
8248             debug( F101, "x25getmsg getmsg bad control block\n", "", errno);
8249             rc = -1;
8250             break;
8251         }
8252
8253         if (result = (N_npi_ctl_t *)control) {
8254             packet_type = result->bind_ack.PRIM_type;
8255             if (packet_type != N_OK_ACK) {
8256                 x25lastmsg = packet_type;
8257             }
8258         }
8259 #ifdef DEBUG
8260         /* printf( "kermit: x25getmsg(): getting " ); */
8261         if (get_ctl->len > 0) {
8262             x25dump_prim(result);
8263         }
8264         debug(F110,
8265               "x25getmsg got packet ",
8266               x25prim( result->bind_ack.PRIM_type ),
8267               0
8268               );
8269 #endif /* DEBUG */
8270
8271         if (get_ctl->len >= (int)sizeof(result->bind_ack.PRIM_type)) {
8272             /* not as pretty as a switch(), but switch can't handle
8273              * runtime variable values :-(
8274              */
8275             if (packet_type == expected ) {
8276                 /* got what we wanted, special case for DATA_IND
8277                  * packets though */
8278                 /* riehm: check Q-bit ? */
8279 #ifdef DEBUG
8280                 printf("x25getmsg(): got expected packet\nrc is %d\n", rc);
8281 #endif /* DEBUG */
8282                 if (packet_type == N_DATA_IND ) {
8283                     /* data received. May be incomplete, even though
8284                      * getmsg returned OK
8285                      */
8286                     if (result->data_ind.DATA_xfer_flags & N_MORE_DATA_FLAG)
8287                         more |= MOREDATA;
8288                     if (result->data_ind.DATA_xfer_flags & N_RC_FLAG)
8289                         printf( "x25getmsg(): data packet wants ack\n" );
8290                 }
8291             } else if( packet_type == N_DISCON_IND) {
8292                 printf( "X25 diconnected\n" );
8293                 /* riehm: need to acknowledge a disconnection? */
8294                 x25clear();
8295                 /* x25unbind( ttyfd ); */
8296                 rc = -1;
8297             } else if( packet_type == N_ERROR_ACK) {
8298                 errno = result->error_ack.UNIX_error;
8299                 perror( "X25 error received" );
8300                 rc = -1;
8301             } else {
8302                 printf("x25getmsg(): failed %s\n", x25err(packet_type));
8303                 rc = -1;
8304             }
8305         }
8306 #ifdef COMMENT
8307         else {
8308             /* Panic - no control data */
8309             printf( "kermit: x25getmsg(): no control data with packet\n" );
8310             rc = -1;
8311         }
8312 #endif /* COMMENT */
8313
8314         if (get_data && (get_data->len >= 0)) {
8315             get_data->buf += get_data->len;
8316             get_data->maxlen -= get_data->len;
8317         }
8318     } while ((rc == 0)
8319              && (get_data && (get_data->maxlen > 0))
8320              && (more & MOREDATA)
8321              );
8322
8323     /* return the file status to its original value, unless its still
8324      * set to -1, or one of the fcntl's failed */
8325     if ((file_status >= 0) && fcntl(fd, F_SETFL, file_status) < 0)
8326         rc = -1;
8327
8328     /*
8329      * Verify that we received an expected primitive
8330      * there is apparantly an error case where the primitive is set
8331      * correctly, but there is not enough data in the control structure
8332      */
8333     if ((packet_type != expected) && (get_ctl->len >= ctl_size) ) {
8334         fprintf(stderr,
8335                 "x25getmsg(): %s NOT received. Primitive received was %s\n",
8336                 x25prim( expected ), x25prim( packet_type ));
8337         debug(F110, "x25getmsg got an unexpected packet ",
8338               x25prim(packet_type),
8339               0
8340               );
8341         rc = -1;
8342     }
8343
8344     if (rc == 0) {
8345         if (get_data && ( get_data->len >= 0)) {
8346             rc = get_data->len;
8347         }
8348     }
8349
8350     if (get_ctl)  { free(get_ctl); get_ctl = NULL; }
8351     if (get_data) { free(get_data); get_data = NULL; }
8352
8353 #ifdef COMMENT
8354 #ifdef DEBUG
8355     printf( "kermit x25getmsg(): returning %d\n", rc );
8356 #endif /* DEBUG */
8357 #endif /* COMMENT */
8358     debug(F110, "x25getmsg returning packet ", x25prim( packet_type ), 0);
8359
8360 #ifdef TRACE
8361     printf( "TRACE: leaving x25getmsg\n" );
8362 #endif /* TRACE */
8363     return(rc);
8364 }
8365
8366 /*****************************************************************************
8367  * Function: x25putmsg()
8368  *
8369  * Description:
8370  *      send a message to a X25 STREAM
8371  *
8372  * Parameters:
8373  *      fd              - file descriptor to x25 device (opened)
8374  *      control         - control buffer (pre-allocated)
8375  *      data            - data buffer (pre-allocated)
8376  *      data_len        - length of data to be transmitted
8377  *      put_flags       - flags for putmsg()
8378  *
8379  * Return Value:
8380  *      >= 0    number of bytes transmitted
8381  *      -1      error
8382  */
8383 int
8384 x25putmsg(fd, control, data, data_len, put_flags)
8385     int                 fd;             /* X25 device (opened) */
8386     N_npi_ctl_t         *control;       /* control buffer (pre-allocated) */
8387     N_npi_data_t        *data;          /* data buffer (pre-allocated) */
8388     int                 data_len;       /* length of data (not the size of
8389                                            the buffer) */
8390     int                 *put_flags;     /* putmsg() flags */
8391 /* x25putmsg */ {
8392     int                 rc = 0;         /* return code */
8393     ulong               type;           /* primitive type */
8394     struct strbuf       *put_ctl = NULL; /* putmsg control */
8395     struct strbuf       *put_data = NULL; /* putmsg data */
8396
8397 #ifdef TRACE
8398     printf( "TRACE: entering x25putmsg\n" );
8399 #endif /* TRACE */
8400
8401 #ifdef DEBUG
8402     printf( "kermit: x25putmsg(): putting " );
8403     x25dump_prim( control );
8404     printf( "\tdata:\t\t" );
8405     x25dump_data( data, 0, data_len );
8406     debug(F110,"x25putmsg: putting packet ",x25prim(control->PRIM_type),0);
8407 #endif /* DEBUG */
8408
8409     if (control) {
8410         put_ctl = (struct strbuf *)malloc( sizeof( struct strbuf ) );
8411         if (put_ctl == NULL) {
8412             perror("kermit x25putmsg(): put_ctl malloc failed\n");
8413             return(-1);
8414         }
8415         put_ctl->maxlen = 0;                    /* unused by putmsg */
8416         put_ctl->len = NPI_MAX_CTL;
8417         put_ctl->buf = (char *)control;
8418     }
8419     if (data && ( data_len > 0)) {
8420         put_data = (struct strbuf *)malloc( sizeof( struct strbuf ) );
8421         if( put_data == NULL) {
8422             perror("kermit x25putmsg(): put_data malloc failed\n");
8423             return(-1);
8424         }
8425         put_data->maxlen = 0;                   /* unused by putmsg */
8426         put_data->len = data_len;
8427         put_data->buf = (char *)data;
8428     }
8429
8430     errno = 0;
8431     rc = putmsg (fd, put_ctl, put_data, 0);
8432     if (rc < 0) {
8433         printf("x25putmsg(): couldn't put %s\n",x25prim(control->PRIM_type));
8434         perror("kermit: x25putmsg(): putmsg failed");
8435         return(-1);
8436     }
8437
8438     /* riehm: this should perhaps be discounted! */
8439     x25lastmsg = control->PRIM_type;
8440
8441 #ifdef COMMENT
8442 #ifdef DEBUG
8443     printf( "kermit debug: x25putmsg() returning %d\n", data_len );
8444 #endif /* DEBUG */
8445 #endif /* COMMENT */
8446     debug( F101, "x25putmsg block size put ", "", data_len);
8447
8448 #ifdef TRACE
8449     printf( "TRACE: leaving x25putmsg\n" );
8450 #endif /* TRACE */
8451
8452     return( data_len );
8453 }
8454
8455 /*****************************************************************************
8456 * Function: x25bind
8457 * Description:  The bind submitted to NPI provides the information required
8458 *               by the packet layer for it to listen for suitable incoming
8459 *               calls.
8460 *
8461 * WARNING:
8462 *
8463 * This routine needs to be called in a completely different manner for
8464 * the client and server side. When starting a client, the
8465 * num_waiting_calls and CUD information should all be set to 0! The
8466 * client's CUD must be inserted in the CONN_REQ data block.
8467 * When starting a server, the CUD must be set to a CUD pattern, and
8468 * the number of waiting calls should be set to a number other than 0.
8469 * (num waiting calls is the number of incomming calls which are to be
8470 * put on hold while the server is servicing another client.)
8471 *
8472 * Who invented this crap?
8473 *
8474 * Parameters:
8475 *       fd              - X25 device (opened)
8476 *       addr            - local address
8477 *       cud             - User Data (null terminated)
8478 *       cud_len         - User Data length
8479 *       num_waiting_calls - number of outstanding calls allowed on this stream
8480 *       line            - logical port number (1)
8481 *       flags           - 0, DEFAULT_LISTENER or TOKEN_REQUEST
8482 *
8483 * Return Value:
8484 *       if binding is successful, 0 is returned for a client, and a token is
8485 *       returned for a server
8486 *
8487 * Return code: 0 if successful
8488 *              -1 if unsuccessful
8489 *****************************************************************************/
8490
8491 ulong
8492 x25bind(fd, addr, cud, cud_len, num_waiting_calls, line, bind_flags)
8493     int fd;                             /* X25 device (opened) */
8494     char * addr;                        /* local address */
8495     char * cud;                         /* Call User Data (null terminated) */
8496     int cud_len;                        /* User Data length */
8497     int num_waiting_calls;              /* Outstanding calls allowed */
8498     int line;                           /* logical port number */
8499     ulong bind_flags;           /* 0, DEFAULT_LISTENER or TOKEN_REQUEST */
8500 /* x25bind */ {
8501     ulong rc;                           /* return code */
8502     int get_flags;                      /* priority flag passed to getmsg */
8503     int put_flags = 0;                  /* output flags for putmsg, always 0 */
8504     ulong type;                         /* primitive type */
8505     N_bind_req_t *bind_req;             /* pointer to N_BIND_REQ primitive */
8506     N_bind_ack_t *bind_ack;             /* pointer to N_BIND_ACK primitive */
8507     char *addtl_info;                   /* pointer to info in addition to
8508                                          * the N_BIND_REQ primitive that is
8509                                          * passed in the control structure
8510                                          * to putmsg */
8511     int addr_len = 0;                   /* length of address string */
8512     ulong bind_req_t_size;              /* for debugging only */
8513
8514 #ifdef TRACE
8515     printf("TRACE: entering x25bind\n" );
8516 #endif /* TRACE */
8517
8518 #ifdef DEBUG
8519     printf("TRACE: x25bind( %d, %s, %s, %d, %d )\n",
8520            fd, addr, cud, line, bind_flags
8521            );
8522 #endif /* DEBUG */
8523
8524     /*
8525      * Allocate  and zero out space to hold the control portion of the
8526      * message passed to putmsg. This will contain the N_BIND_REQ
8527      * primitive and any additional info required for that.
8528      *
8529      * Note: allocated space is the size of the union typedef
8530      * N_npi_ctl_t to allow the use fo the generic x25putmsg routine.
8531      */
8532     bind_req = (N_bind_req_t *) malloc(sizeof( N_npi_ctl_t));
8533     if (bind_req == NULL) {
8534         perror("kermit: x25bind(): bind_req malloc failed");
8535         debug(F100, "x25bind bind_req malloc failed", "", 0);
8536         return(-1);
8537     }
8538     bzero((char *)bind_req, sizeof(N_npi_ctl_t));
8539
8540     /* Build the Bind Request Primitive */
8541     bind_req->PRIM_type = (ulong) N_BIND_REQ;
8542
8543     /* Note that the address length is n+2 and NOT n. Two bytes MUST preceed
8544      * the actual address in an N_BIND_REQ. The first byte contains the
8545      * line number being used with this address, and the second byte is the
8546      * X.121 address prefix, which must be zero.
8547      */
8548     addr_len = strlen(addr);
8549     bind_req->ADDR_length = (ulong) (addr_len + 2);
8550     bind_req->ADDR_offset = (ulong)(sizeof(N_bind_req_t));
8551     bind_req->CONIND_number = (ulong)num_waiting_calls; /* server only */
8552     bind_req->BIND_flags = (ulong) bind_flags; /* 0 in client */
8553     bind_req->PROTOID_length = (ulong) cud_len; /* 0 in client */
8554     if (cud_len == 0) {
8555         bind_req->PROTOID_offset = (ulong) 0;
8556     } else {
8557         /* need to remember the trailing NULL in the address - not
8558          * counted in the address length
8559          */
8560         bind_req->PROTOID_offset
8561           = (ulong) (sizeof(N_bind_req_t) + bind_req->ADDR_length);
8562     }
8563
8564     /*
8565      * Now fill in the additional information required with this primitive
8566      * (address and protocol information (Call User Data))
8567      */
8568     addtl_info = (char *) ((void *)bind_req + bind_req->ADDR_offset);
8569     /*
8570      * The bitwise "&" ensures that the line number is only one byte long
8571      */
8572     *addtl_info++ = (char) line & 0xff;
8573     *addtl_info++ = (char) 0; /* X.121 format */
8574     bcopy( addr, addtl_info, addr_len ); /* include trailing null */
8575     addtl_info += addr_len;
8576     if (cud_len > 0)
8577       bcopy( cud, addtl_info, cud_len );
8578     /*
8579      * Call putmsg() to put the bind request message on the stream
8580      */
8581     if (x25putmsg(fd,
8582                   (N_npi_ctl_t*)bind_req,
8583                   (N_npi_data_t *)NULL,
8584                   0,
8585                   &put_flags
8586                   ) < 0) {
8587         printf( "kermit: x25bind(): x25putmsg failed\n" );
8588         return(-1);
8589     }
8590
8591     /*
8592      * Allocate and zero out space for the N_BIND_ACK primitive
8593      */
8594     bind_ack = (N_bind_ack_t *) malloc(sizeof(N_npi_ctl_t));
8595     if (bind_ack == NULL){
8596         perror("kermit: x25bind(): bind_ack malloc failed");
8597         return(-1);
8598     }
8599     bzero(bind_ack, sizeof(N_npi_ctl_t));
8600     /*
8601      * Initialize the control structure and flag variable sent to getmsg
8602      */
8603     get_flags=0;
8604
8605     /* get the ACK for the bind */
8606 #ifdef DEBUG
8607     printf( "kermit: x25bind() trying to get a BIND_ACK\n" );
8608 #endif /* DEBUG */
8609     rc = (ulong)x25getmsg( fd, (N_npi_ctl_t*)bind_ack,
8610             (int)sizeof( N_bind_ack_t ), (N_npi_data_t*)NULL, 0, &get_flags,
8611             N_BIND_ACK );
8612
8613     /* turn quantitive return code into a qualitative one */
8614     if (rc > 0) rc = 0;
8615
8616     /* if all went well, get the token from the acknowledgement packet */
8617     if ((bind_flags & TOKEN_REQUEST ) && ( rc >= 0)) {
8618         rc = bind_ack->TOKEN_value;
8619     }
8620
8621     /* free up the memory we allocated earlier */
8622     free(bind_req);
8623     free(bind_ack);
8624
8625 #ifdef TRACE
8626     printf( "TRACE: leaving x25bind\n" );
8627 #endif /* TRACE */
8628
8629     return( rc );
8630 }
8631
8632 /*****************************************************************************
8633 * Function: x25call
8634 * Description:  This routine builds and sends an N_CONN_REQ primitive, then
8635 *               checks for an N_CONN_CON primitive in return.
8636 *
8637 * Parameters:
8638 * fd    - file descriptor of stream
8639 * caddr - called address (remote address)
8640 *
8641 * Functions Referenced:
8642 * malloc()
8643 * bzero()
8644 * getmsg()
8645 * putmsg()
8646 *
8647 * Return code:
8648 * 0 - if successful
8649 * -1 if not successful
8650 *****************************************************************************/
8651 int
8652 x25call(fd, remote_nua, cud)
8653     int fd;                             /* X25 device (opened) */
8654     char * remote_nua;                  /* remote address to call */
8655     char * cud;                         /* call user data */
8656 /* x25call */ {
8657     int rc;                             /* return code */
8658     int flags;                          /* Connection flags */
8659     int get_flags;                      /* priority flags for getmsg */
8660     ulong type;                         /* primitive type */
8661     N_conn_req_t *connreq_ctl;          /* pointer to N_CONN_REQ primitive */
8662     N_npi_data_t *connreq_data;         /* pointer to N_CONN_REQ data (CUD) */
8663     int connreq_data_len;               /* length of filled data buffer */
8664     N_conn_con_t *conncon_ctl;          /* pointer to N_CONN_CON primitive */
8665     N_npi_data_t *conncon_data;         /* pointer to any data associated with
8666                                          * the N_CONN_CON primitive */
8667     char *addtl_info;                   /* pointer to additional info needed
8668                                          * for N_CONN_REQ primitive */
8669     int addr_len;                       /* length of address */
8670
8671 #ifdef TRACE
8672     printf( "TRACE: entering x25call\n" );
8673 #endif /* TRACE */
8674
8675 #ifdef DEBUG
8676     printf( "x25call( %d, %s )\n", fd, remote_nua );
8677     printf( "connecting to %s on fd %d\n", remote_nua, fd );
8678 #endif /* DEBUG */
8679
8680     /*
8681      * Allocate and zero out space for the N_CONN_REQ primitive
8682      * use the size of the generic NPI primitive control buffer
8683      */
8684     connreq_ctl  = (N_conn_req_t *) malloc(sizeof(N_npi_ctl_t));
8685     if (connreq_ctl == NULL){
8686         perror("kermit: x25call(): connreq_ctl malloc failed");
8687         return(-1);
8688     }
8689     bzero(connreq_ctl,sizeof(N_npi_ctl_t));
8690     /*
8691      * Build the Connection Request Primitive
8692      */
8693     flags = 0;
8694     connreq_ctl->PRIM_type = (ulong) N_CONN_REQ;
8695
8696     /* Note that the address length is nchai+1 and not n+2. The line number
8697      * is only passed with the address for the bind. The first byte of
8698      * the address for the N_CONN primitives contains the X.121
8699      * address prefix, which must be zero. The remaining bytes are the
8700      * address itself.
8701      */
8702     addr_len = strlen( remote_nua );
8703     connreq_ctl->DEST_length = (ulong) (addr_len + 1);
8704     connreq_ctl->DEST_offset = (ulong) sizeof(N_conn_req_t);
8705     /* connreq_ctl->CONN_flags = (ulong)EX_DATA_OPT | REC_CONF_OPT; */
8706     connreq_ctl->CONN_flags = (ulong) 0;
8707     connreq_ctl->QOS_length = (ulong) 0;        /* unsupported in AIX 4.1 */
8708     connreq_ctl->QOS_offset = (ulong) 0;        /* unsupported in AIX 4.1 */
8709
8710     addtl_info = (char *) ((void*)connreq_ctl + connreq_ctl->DEST_offset);
8711     *addtl_info++ = (char) 0; /* X.121 format */
8712     bcopy( remote_nua, addtl_info, addr_len );
8713
8714     /*
8715      * setup the data buffer for the connection request
8716      */
8717     connreq_data  = (N_npi_data_t *) malloc(sizeof(N_npi_data_t));
8718     if (connreq_data == NULL){
8719         perror("kermit: x25call(): connreq_data malloc failed");
8720         return(-1);
8721     }
8722     bzero(connreq_data,sizeof(N_npi_data_t));
8723
8724     /* facility selection needs to be put in the front of connreq_data */
8725     connreq_data_len = 0;
8726     connreq_data_len += x25facilities( (char *)connreq_data );
8727     if (cud && *cud) {
8728         bcopy(cud,
8729               (char *)((char *)connreq_data + connreq_data_len),
8730               strlen(cud)
8731               );
8732         connreq_data_len += strlen( cud );
8733         }
8734
8735     /*
8736      * Call putmsg() to put the connection request message on the stream
8737      */
8738     rc = x25putmsg( fd, (N_npi_ctl_t*)connreq_ctl, connreq_data,
8739             connreq_data_len, &flags );
8740     if (rc < 0) {
8741         return(-1);
8742     }
8743
8744     /*
8745      * Allocate and zero out space for the N_CONN_CON primitive
8746      */
8747     if ((conncon_ctl = (N_conn_con_t *) malloc(sizeof(N_npi_ctl_t))) == NULL) {
8748         perror("kermit: x25call(): conncon_ctl malloc failed");
8749         return(-1);
8750     }
8751     bzero(conncon_ctl, sizeof(N_npi_ctl_t));
8752
8753     /*
8754      * Allocate and zero out space for any data associated with N_CONN_CON
8755      */
8756     if ( (conncon_data = (N_npi_data_t *) malloc(NPI_MAX_DATA)) == NULL) {
8757         perror("kermit: x25call(): conncon_data malloc failed");
8758         return(-1);
8759     }
8760     bzero(conncon_data, NPI_MAX_DATA);
8761
8762     /* Initialize and build the structures for getmsg */
8763     get_flags=0;
8764
8765     rc = x25getmsg( fd, (N_npi_ctl_t*)conncon_ctl, (int)sizeof( N_conn_con_t ),
8766             conncon_data, NPI_MAX_DATA, &get_flags, N_CONN_CON );
8767
8768     /* turn quantitive return code into a qualitative one */
8769     if (rc > 0) rc = 0;
8770
8771     /* Free the space that we no longer need */
8772     if (connreq_ctl) { free(connreq_ctl); connreq_ctl = NULL; }
8773     if (conncon_ctl) { free(conncon_ctl); conncon_ctl = NULL; }
8774     if (conncon_data) { free(conncon_data); conncon_data = NULL; }
8775
8776 #ifdef TRACE
8777     printf( "TRACE: leaving x25call\n" );
8778 #endif /* TRACE */
8779
8780     return(rc);
8781 }
8782
8783 /*****************************************************************************
8784  * Function: x25getcall
8785  *
8786  * Description: This routine checks for an incomming call, verified
8787  * that it is a CONNIND (connection indication) message, and then
8788  * accepts the call and returns the file descriptor of the new stream
8789  *
8790  * Parameters:
8791  * fd   - file descriptor of listening stream
8792  *
8793  * Return Codes:
8794  * callfd       - file descriptor of connected incomming call.
8795  *              - set to -1 if an error occured
8796  *
8797  *****************************************************************************/
8798 int
8799 x25getcall(fd) int fd; {
8800     int x25callfd;                      /* fd of incomming call */
8801     N_conn_ind_t *connind_ctl;          /* connind controll buffer */
8802     N_npi_data_t *connind_data;         /* connind data buffer */
8803     int get_flags;                      /* flags for getmsg */
8804     ulong flags;                        /* connection flags */
8805     int rc;                             /* return code */
8806
8807     extern x25addr_t remote_nua;        /* remote X.25 addr global var */
8808
8809 #ifdef TRACE
8810     printf( "TRACE: entering x25getcall\n" );
8811 #endif /* TRACE */
8812
8813     /* allocate space for connection indication buffers */
8814     if ((connind_ctl = (N_conn_ind_t *)malloc(sizeof(N_npi_ctl_t))) == NULL) {
8815         perror("kermit: x25getcall(): connind_ctl malloc failed");
8816         return (-1);
8817     }
8818     bzero(connind_ctl, sizeof(N_npi_ctl_t));
8819
8820     if ((connind_data = (N_npi_data_t *)malloc(NPI_MAX_DATA)) == NULL) {
8821         perror("kermit: x25getcall(): connind_data malloc failed");
8822         return (-1);
8823     }
8824     bzero(connind_data, NPI_MAX_DATA);
8825
8826     /* initialise control structures */
8827     get_flags = 0;
8828
8829     /* call getmsg to check for a connection indication */
8830     if (x25getmsg(fd,
8831                   (N_npi_ctl_t*)connind_ctl,
8832                   (int)sizeof(N_conn_ind_t),
8833                   connind_data,
8834                   NPI_MAX_DATA,
8835                   &get_flags,
8836                   N_CONN_IND
8837                   ) < 0) {
8838 #ifdef DEBUG
8839         printf( "x25getcall(): errno is: %d\n", errno );
8840 #endif /* DEBUG */
8841         perror ("x25getcall(): getmsg failed");
8842         return(-1);
8843     }
8844
8845     /* a connection indication was received
8846      * - pull it to bits and answer the call
8847      */
8848     x25seqno = connind_ctl->SEQ_number;
8849     flags = connind_ctl->CONN_flags;
8850 #ifdef DEBUG
8851     printf( "setting remote_nua to a new value due to incomming call\n" );
8852 #endif /* DEBUG */
8853     /*
8854      * no guarantee that the address is null terminated, ensure that
8855      * after copying that it is (assumption: remote_nua is longer than
8856      * the address + 1)
8857      */
8858     bzero(remote_nua, sizeof(remote_nua));
8859     /* note: connind_ctl contains a x121 address, which has a null as
8860      * the FIRST character - strip it off!
8861      */
8862     ckstrncpy(remote_nua,
8863             (char*)((char*)connind_ctl + connind_ctl->SRC_offset + 1),
8864             connind_ctl->SRC_length - 1
8865             );
8866 #ifdef DEBUG
8867     printf( "remote_nua set to new value of %s\n", remote_nua );
8868 #endif /* DEBUG */
8869
8870     /* errors handled by callee */
8871     x25callfd = x25accept(x25seqno, flags);
8872
8873     /* free the malloc'd buffers */
8874     if (connind_ctl) { free(connind_ctl); connind_ctl = NULL; }
8875     if (connind_data) { free(connind_data); connind_data = NULL; }
8876
8877 #ifdef TRACE
8878     printf( "TRACE: leaving x25getcall\n" );
8879 #endif /* TRACE */
8880
8881     /* return the file descriptor (or error if < 0) */
8882     return( x25callfd );
8883 }
8884
8885 /*****************************************************************************
8886  * Function: x25accept
8887  *
8888  * Description: accept an incomming call
8889  *              This essentially means opening a new STREAM and sending
8890  *              an acknowledge back to the caller.
8891  *
8892  * Parameters:
8893  *      seqno   - sequence number for acknowledgement
8894  *      flags   - flags passed to us by the caller
8895  *
8896  * Return Codes:
8897  *      fd      - file descriptor of new STREAM
8898  *                set to -1 if an error occured
8899  *
8900  *****************************************************************************/
8901 int
8902 x25accept(seqno,flags)
8903     ulong seqno;                        /* connection sequence number */
8904     ulong flags;                        /* connection flags */
8905 /* x25accept */ {
8906     int x25callfd;                      /* fd for incomming call */
8907     int get_flags;                      /* priority flags for getmsg */
8908     int put_flags = 0;                  /* flags for putmsg, always 0 */
8909     int addr_len;                       /* length of local address */
8910     ulong token;                        /* connection token */
8911     N_conn_res_t *conn_res;             /* N_CONN_RES primitive */
8912     N_ok_ack_t *ok_ack;                 /* N_OK_ACK primitive */
8913     char *addtl_info;                   /* temp pointer */
8914     int rc;                             /* temporary return code */
8915
8916 /* global variables from ckcmai.c */
8917     extern int revcall, closgr, cudata;
8918     extern char udata[];
8919     extern x25addr_t local_nua;         /* local X.25 address */
8920     extern char x25name[];              /* x25 device name (sx25a0) */
8921     extern char x25dev[];               /* x25 device file /dev/x25pkt */
8922     extern int x25port;                 /* logical port to use */
8923     ulong bind_flags = 0;               /* flags for binding the X25 stream */
8924
8925 #ifdef TRACE
8926     printf( "TRACE: entering x25accept\n" );
8927 #endif /* TRACE */
8928
8929     /* open a new packet level stream */
8930     if ((x25callfd = open(x25dev, O_RDWR)) < 0) {
8931         perror ("kermit: x25accept(): X.25 device open error");
8932         debug(F101,"x25accept() device open error","",errno);
8933         return(-1);
8934     }
8935
8936     /* push the NPI onto the STREAM */
8937     if (ioctl(x25callfd,I_PUSH,"npi") < 0) {
8938         perror( "kermit: x25accept(): couldn't push npi on the X25 stream" );
8939         debug(F101,"x25accept can't push npi on the X25 stream","",errno);
8940         return (-1);
8941     }
8942
8943     /* bind kermit server to the local X25 address */
8944     /* taken from /usr/samples/sx25/npi/npiserver.c (AIX 4) */
8945     bind_flags |= TOKEN_REQUEST;
8946     token = x25bind(x25callfd,local_nua,(char *)NULL,0,0,x25port,bind_flags);
8947     if (token < 0) {
8948         printf( "kermit: x25accept(): couldn't bind to local X25 address\n" );
8949         netclos();
8950         return(-1);
8951     }
8952
8953     /* allocate connection response primitive */
8954     if ((conn_res = (N_conn_res_t *)malloc( NPI_MAX_CTL )) == NULL) {
8955         perror("kermit: x25accept(): conn_res malloc failed");
8956         return (-1);
8957     }
8958     bzero((char *)conn_res, NPI_MAX_CTL);
8959
8960     /* setup connection response primitive */
8961     addr_len = strlen( local_nua );
8962     conn_res->PRIM_type = (ulong)N_CONN_RES;
8963     conn_res->TOKEN_value = token;
8964     /* note address length is n+1 to accomodate the X.121 address prefix */
8965     conn_res->RES_length = (ulong)(addr_len + 1);
8966     conn_res->RES_offset = (ulong)sizeof( N_conn_res_t );
8967     conn_res->SEQ_number = seqno;
8968     conn_res->CONN_flags = 0;
8969     conn_res->QOS_length = 0;           /* unsupported - must be 0 (!?) */
8970     conn_res->QOS_offset = 0;
8971
8972     addtl_info = (char *)((char *)conn_res + conn_res->RES_offset);
8973     *addtl_info++ = (char)0;    /* X.121 address prefix */
8974     bcopy( local_nua, addtl_info, addr_len );
8975
8976     /*
8977      * send off the connect response
8978      */
8979     if (x25putmsg(x25callfd,
8980                   (N_npi_ctl_t*)conn_res,
8981                   (N_npi_data_t *)NULL,
8982                   0,
8983                   &put_flags
8984                   ) < 0 ) {
8985         perror("kermit: x25accept(): putmsg connect response failed");
8986         return(-1);
8987     }
8988
8989     /*
8990      * Allocate and zero out space for the OK_ACK primitive
8991      */
8992     if ((ok_ack = (N_ok_ack_t *) malloc(sizeof(N_npi_ctl_t))) == NULL) {
8993         perror("kermit: x25call(): ok_ack malloc failed");
8994         return(-1);
8995     }
8996     bzero(ok_ack, sizeof(N_npi_ctl_t));
8997
8998     /* Initialize and build the structures for getmsg */
8999     get_flags=0;
9000
9001     rc = (int)x25getmsg(x25callfd,
9002                         (N_npi_ctl_t*)ok_ack,
9003                         (int)sizeof(N_ok_ack_t),
9004                         (N_npi_data_t*)NULL,
9005                         0,
9006                         &get_flags,
9007                         N_OK_ACK
9008                         );
9009     if (rc == 0) {
9010         /* sequence number is only for disconnecting when not connected !? */
9011         x25seqno = 0;
9012     }
9013
9014     /* free up malloc'ed buffer space */
9015     if (conn_res) { free(conn_res); conn_res = NULL; }
9016     if (ok_ack) { free(ok_ack); ok_ack = NULL; }
9017
9018 #ifdef TRACE
9019     printf( "TRACE: leaving x25accept\n" );
9020 #endif /* TRACE */
9021
9022     return( ( rc >= 0 ) ? x25callfd : -1 );
9023 }
9024
9025 /*****************************************************************************
9026  * Function: x25unbind
9027  *
9028  * Description:  This subroutine builds and sends an unbind request and gets
9029  * the acknowledgement for it.
9030  *
9031  * Parameters:
9032  * fd - File descriptor of the stream
9033  *
9034  * Functions Referenced:
9035  * getmsg()
9036  * putmsg()
9037  * malloc()
9038  * bzero()
9039  *
9040  * Return code:
9041  * 0 - if successful
9042  * -1 - if not successful
9043  *****************************************************************************/
9044 int
9045 x25unbind(fd) int fd; {                 /* X25 device (opened) */
9046     int rc;                             /* return code */
9047     int flags;                          /* bind flags */
9048     int get_flags;                      /* priority flag for getmsg */
9049     ulong type;                         /* primitive type */
9050     N_unbind_req_t *unbind_req;         /* pointer to N_UNBIND_REQ */
9051     N_ok_ack_t *ok_ack;                 /* pointer to N_OK_ACK */
9052
9053 #ifdef TRACE
9054     printf( "TRACE: entering x25unbind\n" );
9055 #endif /* TRACE */
9056
9057 #ifdef DEBUG
9058     /* printf( "x25unbind( %d )\n", fd ); */
9059 #endif /* DEBUG */
9060     debug(F101,"x25unbind closing x25 connection #","",fd);
9061
9062     /* Allocate and zero out space to hold the N_UNBIND_REQ primitive */
9063     unbind_req = (N_unbind_req_t *) malloc(sizeof(N_npi_ctl_t));
9064     if (unbind_req == NULL) {
9065         perror("kermit: x25unbind(): unbind_req malloc failed");
9066         return(-1);
9067     }
9068     bzero(unbind_req, sizeof(N_npi_ctl_t));
9069
9070     /*
9071      * Build the Unbind Request Primitive
9072      */
9073     flags = 0;
9074     unbind_req->PRIM_type = (ulong) N_UNBIND_REQ;
9075
9076     /*
9077      * Call putmsg() to put the bind request message on the stream
9078      */
9079     if (x25putmsg(fd,
9080                   (N_npi_ctl_t*)unbind_req,
9081                   (N_npi_data_t *)NULL,
9082                   0,
9083                   &flags
9084                   ) < 0) {
9085         perror ("kermit: x25unbind(): putmsg failed");
9086         return(-1);
9087     }
9088
9089     /* Allocate and Zero out space for the N_OK_ACK primitive */
9090     ok_ack = (N_ok_ack_t *) malloc(sizeof(N_npi_ctl_t));
9091     if (ok_ack == NULL) {
9092         perror("kermit x25unbind(): ok_ack malloc failed\n");
9093         return(-1);
9094     }
9095     bzero(ok_ack, sizeof(N_npi_ctl_t));
9096
9097     /* Initialize and build the control structure for getmsg */
9098     get_flags=0;
9099
9100     /* Call getmsg() to check for an acknowledgement */
9101     rc = x25getmsg(fd,
9102                    (N_npi_ctl_t*)ok_ack,
9103                    (int)sizeof(N_ok_ack_t),
9104                    (N_npi_data_t*)NULL,
9105                    0,
9106                    &get_flags,
9107                    N_OK_ACK
9108                    );
9109     if (rc < 0) {
9110         perror ("kermit: x25unbind: getmsg failed");
9111         return(-1);
9112     }
9113
9114     /* Free up the space that we no longer need */
9115     if (unbind_req) { free(unbind_req); unbind_req = NULL; }
9116     if (ok_ack) { free(ok_ack); ok_ack = NULL; }
9117
9118 #ifdef TRACE
9119     printf( "TRACE: leaving x25unbind\n" );
9120 #endif /* TRACE */
9121
9122     return(0);
9123 }
9124
9125 /*****************************************************************************
9126  * Function: x25xin
9127  *
9128  * Description:
9129  *      Read n characters from X.25 circuit into buf (AIX only)
9130  *
9131  * Parameters:
9132  *      data_buf_len    maximum size of data buffer
9133  *      data_buf        pointer to pre-allocated buffer space
9134  *
9135  * Return Value:
9136  *      the number of characters actually read
9137  */
9138 int
9139 x25xin(data_buf_len,data_buf) int data_buf_len; CHAR *data_buf; {
9140     struct strbuf getmsg_ctl;           /* streams control structure */
9141     struct strbuf getmsg_data;          /* streams data structure */
9142     int rc = 0;                         /* return code */
9143     int getmsg_flags;                   /* packet priority flags */
9144     char * ctl_buf;                     /* npi control buffer */
9145     N_npi_ctl_t * result;               /* pointer to simplify switch() */
9146
9147 #ifdef TRACE
9148     printf( "TRACE: entering x25xin\n" );
9149 #endif /* TRACE */
9150
9151     /* ensure that no maximum's are overridden */
9152     data_buf_len = (NPI_MAX_DATA < data_buf_len) ? NPI_MAX_DATA : data_buf_len;
9153
9154     /* allocate space for packet control info */
9155     if ((ctl_buf = (char *)malloc(NPI_MAX_CTL)) == NULL) {
9156         perror( "kermit: x25xin(): ctl_buf malloc" );
9157         return(-1);
9158     }
9159 #ifdef COMMENT
9160     /* riehm: need zeroed buffer for getmsg? */
9161     bzero( ctl_buf, NPI_MAX_CTL );
9162     /* clear data buffer */
9163     bzero( data_buf, data_buf_len );
9164 #endif /* COMMENT */
9165
9166     getmsg_flags = 0;                   /* get the first packet available */
9167
9168     rc = x25getmsg(ttyfd,
9169                    ctl_buf,
9170                    NPI_MAX_CTL,
9171                    data_buf,
9172                    data_buf_len,
9173                    &getmsg_flags,
9174                    N_DATA_IND
9175                    );
9176 #ifdef COMMENT
9177 #ifdef DEBUG
9178     if (rc >= 0) {
9179         printf( "kermit: x25xin(): got " );
9180         x25dump_data( data_buf, 0, rc );
9181     } else {
9182         printf( "x25xin(): attempt to get data resulted in an error\n" );
9183     }
9184 #endif /* DEBUG */
9185 #endif /* COMMENT */
9186
9187     /* free buffers */
9188     if (ctl_buf) { free(ctl_buf); ctl_buf = NULL; }
9189
9190 #ifdef TRACE
9191     printf( "TRACE: leaving x25xi\n" );
9192 #endif /* TRACE */
9193
9194     return(rc);
9195 }
9196
9197 /*****************************************************************************
9198  * Function: x25write
9199  *
9200  * Description:
9201  *      write a block of characters to the X25 STREAM (AIX)
9202  *
9203  * Parameters:
9204  *      fd              file descriptor to write to
9205  *      databuf         buffer containing data to write
9206  *      databufsize             size of the buffer to write
9207  *
9208  * Return Value:
9209  *      size            the number of bytes actually transmitted
9210  */
9211 int
9212 x25write(fd, databuf, databufsize)
9213     int         fd;                  /* X25 STREAMS file descriptor (ttyfd) */
9214     char        *databuf;               /* buffer to write */
9215     int         databufsize;            /* buffer size */
9216 /* x25write */ {
9217     N_data_req_t *data_req_ctl;
9218     int rc;                             /* return code (size transmitted) */
9219     int write_flags = 0;                /* always 0 !? */
9220
9221 #ifdef TRACE
9222     printf( "TRACE: entering x25write\n" );
9223 #endif /* TRACE */
9224
9225     if ((data_req_ctl = (N_data_req_t *)malloc(NPI_MAX_CTL) ) == NULL) {
9226         perror( "kermit: x25write(): data_req_ctl malloc" );
9227         return(-1);
9228     }
9229     data_req_ctl->PRIM_type = N_DATA_REQ;
9230     data_req_ctl->DATA_xfer_flags = 0;
9231
9232     /* riehm: possible extension
9233      * possibly need to think about splitting up the data buffer
9234      * into multiple parts if databufsize > NPI_MAX_DATA
9235      */
9236
9237 #ifdef COMMENT
9238 #ifdef DEBUG
9239     printf( "kermit: x25write(): writing data to x25 stream\n" );
9240     printf( "\tdata:\t" );
9241     x25dump_data(databuf, 0, databufsize);
9242 #endif /* DEBUG */
9243 #endif /* COMMENT */
9244     rc = x25putmsg(fd,
9245                    (N_npi_ctl_t*)data_req_ctl,
9246                    (N_npi_data_t*)databuf,
9247                    databufsize,
9248                    &write_flags
9249                    );
9250     if (data_req) { free(data_req_ctl);  data_req = NULL; }
9251
9252 #ifdef TRACE
9253     printf( "TRACE: leaving x25write\n" );
9254 #endif /* TRACE */
9255
9256     return(rc);
9257 }
9258
9259 /*****************************************************************************
9260  * Function: x25local_nua
9261  *
9262  * Description:
9263  *      This routine is only interesting for IBM computers. In order
9264  *      to set up a connection (see x25bind()) you need to know the
9265  *      local NUA (x25 address). Unfortunately, you need all this code
9266  *      to find that out, I just hope this works for everyone else!
9267  *
9268  * Parameters:
9269  *      a pre-allocated character buffer, long enough to hold an X.25 address
9270  *      and the tailing null.
9271  *
9272  * Return Value:
9273  *      the length of the address string.
9274  *      0 = error
9275  */
9276 int
9277 x25local_nua(char *buf) {
9278     struct CuAt *response;      /* structure to fill with info from ODM */
9279     CLASS_SYMBOL retClass;      /* ODM class */
9280     char query[64];             /* odm database query */
9281     int rc = 0;                 /* return value (length of local NUA) */
9282     extern char x25name[];      /* x25 device name (sx25a0) */
9283
9284 #ifdef TRACE
9285     printf( "TRACE: entering x25local_nua\n" );
9286 #endif /* TRACE */
9287
9288     /* set up query string */
9289     if (x25name[0] == '\0') {
9290 #ifdef DEBUG
9291         printf( "kermit: x25local_nua(): No x25 device set, trying sx25a0\n" );
9292 #endif /* DEBUG */
9293         strcpy( x25name, "sx25a0" );
9294     }
9295     ckmakmsg(query, sizeof(query), "name like ",x25name,
9296              " and attribute like local_nua");
9297
9298     /* initialise ODM database */
9299     odmerrno = 0;
9300     if (odm_initialize() == -1) {
9301         printf( "x25local_nua(): can't initialize ODM database");
9302         switch (odmerrno) {
9303           case ODMI_INVALID_PATH:
9304             printf( "invalid path\n" );
9305             break;
9306           case ODMI_MALLOC_ERR:
9307             printf( "malloc failed\n" );
9308             break;
9309           default:
9310             printf( "unknown error %d\nPlease call IBM\n", odmerrno );
9311         }
9312         return(rc);
9313     }
9314
9315     /* open the CuAt class */
9316     retClass = odm_open_class(CuAt_CLASS);
9317     if (((int)retClass) == -1) {
9318         printf( "kermit: x25local_nua(): can't open CuAt class in odm. " );
9319         switch (odmerrno) {
9320           case ODMI_CLASS_DNE:
9321             printf( "CuAt class doesn't exist\n" );
9322             break;
9323           case ODMI_CLASS_PERMS:
9324             printf( "permission to CuAt class file denied\n" );
9325             break;
9326           case ODMI_MAGICNO_ERR:
9327             printf( "CuAt is an invalid ODM object class\n" );
9328             break;
9329           case ODMI_OPEN_ERR:
9330             printf( "cannot open CuAt class - and don't know why!\n" );
9331             break;
9332           case ODMI_INVALID_PATH:
9333             printf( "invalid path\n" );
9334             break;
9335           case ODMI_TOOMANYCLASSES:
9336             printf( "too many object classes have been opened\n" );
9337             break;
9338           default:
9339             printf( "unknown error %d\nPlease call IBM\n", odmerrno );
9340         }
9341         return(rc);
9342     }
9343
9344 #ifdef DEBUG
9345     printf("retClass= %d\n", retClass);
9346 #endif /* DEBUG */
9347
9348     response = (struct CuAt *)odm_get_first( retClass, query, NULL );
9349     if (((int)response) == -1) {
9350         printf( "kermit: x25local_nua(): odm query failed " );
9351         switch (odmerrno) {
9352           case ODMI_BAD_CRIT:           /* Programming error */
9353             printf( "bad search criteria\n" );
9354             break;
9355           case ODMI_CLASS_DNE:
9356             printf( "CuAt class doesn't exist\n" );
9357             break;
9358           case ODMI_CLASS_PERMS:
9359             printf( "permission to CuAt class file denied\n" );
9360             break;
9361           case ODMI_INTERNAL_ERR:
9362             printf("odm internal error\nPlease contact your administrator\n" );
9363             break;
9364           case ODMI_INVALID_CLXN:
9365             printf("CuAt is invalid or inconsistent odm class collection\n");
9366             break;
9367           case ODMI_INVALID_PATH:
9368             printf( "invalid path\n" );
9369             break;
9370           case ODMI_MAGICNO_ERR:
9371             printf( "CuAt is an invalid ODM object class\n" );
9372             break;
9373           case ODMI_MALLOC_ERR:
9374             printf( "malloc failed\n" );
9375             break;
9376           case ODMI_OPEN_ERR:
9377             printf( "cannot open CuAt class - and don't know why!\n" );
9378             break;
9379           case ODMI_TOOMANYCLASSES:
9380             printf( "too many object classes have been opened\n" );
9381             break;
9382           default:
9383             printf( "unknown error %d\nPlease call IBM\n", odmerrno );
9384         }
9385         return(rc);
9386     }
9387
9388     /* check for a meaningfull response */
9389     if (response != NULL) {
9390         if (response->value != NULL) {
9391             strcpy(buf, response->value);
9392             rc = strlen( buf );
9393 #ifdef DEBUG
9394 /*
9395             printf( "attribute name is: %s\n", (char *)response->attribute );
9396             printf( "I think my address is %s\n", (char*)response->value );
9397 */
9398 #endif /* DEBUG */
9399         } else {
9400             printf( "kermit: x25local_nua(): couldn't find the local NUA\n" );
9401         }
9402     } else {
9403         switch (odmerrno) {
9404           case ODMI_BAD_CRIT:
9405             printf( "Error: ODMI_BAD_CRIT - bad criteria\n" );
9406             break;
9407           case ODMI_CLASS_DNE:
9408             printf( "Error: ODMI_CLASS_DNE - class doesn't exist\n" );
9409             break;
9410           case ODMI_CLASS_PERMS:
9411             printf( "Error: ODMI_CLASS_PERMS - class permissions\n" );
9412             break;
9413           case ODMI_INTERNAL_ERR:
9414             printf( "Error: ODMI_INTERNAL_ERR - panic\n" );
9415             break;
9416           case ODMI_INVALID_CLXN:
9417             printf( "Error: ODMI_INVALID_CLXN - invalid collection\n" );
9418             break;
9419           case ODMI_INVALID_PATH:
9420             printf( "Error: ODMI_INVALID_PATH - invalid path - what path?\n" );
9421             break;
9422           case ODMI_MAGICNO_ERR:
9423             printf( "Error: ODMI_MAGICNO_ERR - invalid object magic\n" );
9424             break;
9425           case ODMI_MALLOC_ERR:
9426             printf( "Error: ODMI_MALLOC_ERR - malloc failed\n" );
9427             break;
9428           case ODMI_OPEN_ERR:
9429             printf( "Error: ODMI_OPEN_ERR - cannot open class\n" );
9430             break;
9431           case ODMI_TOOMANYCLASSES:
9432             printf( "Error: ODMI_TOOMANYCLASSES - too many classes\n" );
9433             break;
9434           default:
9435             printf( "Unknown error!\n" );
9436         }
9437         return(rc);
9438     }
9439
9440     /* close the database again */
9441     odm_close_class( retClass );
9442
9443     /* forget about ODM all together */
9444     odm_terminate();
9445
9446 #ifdef TRACE
9447     printf( "TRACE: leaving x25local_nua\n" );
9448 #endif /* TRACE */
9449
9450     debug(F110, "x25local_nua local address is ", buf, 0);
9451     return(rc);
9452 }
9453
9454 /*****************************************************************************
9455  * Function: x25facilities
9456  *
9457  * Description:
9458  *      build up the facilities data packet for a connection request
9459  *
9460  * Parameters:
9461  *      a pre-allocated char buffer, normally NPI_MAX_DATA big.
9462  *
9463  * Return Value:
9464  *      the number of characters inserted into the buffer
9465  */
9466 int
9467 x25facilities(buffer) char *buffer; {
9468     extern int revcall;
9469     extern int closgr;
9470     char *p;                            /* temp pointer */
9471     char *start;                        /* temp pointer */
9472
9473 #ifdef TRACE
9474     printf( "TRACE: entering x25facilities\n" );
9475 #endif /* TRACE */
9476
9477     p = buffer + 1;
9478     start = p;
9479
9480 #ifdef DEBUG
9481     printf( "kermit: x25facilities(): getting X25 facilities\n" );
9482 #endif /* DEBUG */
9483
9484     if (revcall != 0) {
9485 #ifdef DEBUG
9486         printf("reverse charge: %d\n", revcall );
9487 #endif /* DEBUG */
9488         *++p = 0x01;
9489         *++p = revcall;
9490     }
9491     if (closgr > 0) {
9492 #ifdef DEBUG
9493         printf("closed user group: %d\n", closgr );
9494 #endif /* DEBUG */
9495         *++p = 0x03;
9496         *++p = closgr;
9497     }
9498
9499 #ifdef DEBUG
9500     if (p == start) {
9501         printf( "no facilities\n" );
9502     }
9503 #endif /* DEBUG */
9504
9505     /* set the size of the facilities buffer */
9506     *buffer = (char)( p - start ) & 0xff;
9507
9508 #ifdef DEBUG
9509     printf( "kermit: x25facilities(): returning %d\n", (int)(p - buffer)  );
9510 #endif /* DEBUG */
9511
9512 #ifdef TRACE
9513     printf( "TRACE: leaving x25facilities\n" );
9514 #endif /* TRACE */
9515
9516     /* return the size of the facilities with size byte */
9517     /* 1 == no facilities, 0 byte returned as facilities size */
9518     return( (int)(p - buffer) );
9519 }
9520
9521 /*
9522  * reset the connection
9523  */
9524 int
9525 x25reset(cause, diagn) char cause; char diagn; {
9526     /* not implemented */
9527
9528 #ifdef TRACE
9529     printf( "TRACE: entering x25reset\n" );
9530 #endif /* TRACE */
9531
9532 #ifdef TRACE
9533     printf( "TRACE: leaving x25reset\n" );
9534 #endif /* TRACE */
9535
9536     return(0);
9537 }
9538
9539 /*
9540  * clear the x25 connection - ie: hang up
9541  */
9542 int
9543 x25clear() {
9544     int get_flags = 0;                  /* priority flag for getmsg */
9545     int put_flags = 0;                  /* send flags, always 0 */
9546     ulong type;                         /* primitive type */
9547     N_discon_req_t *discon_req;         /* pointer to N_DISCON_REQ */
9548     N_discon_ind_t *discon_ind;         /* pointer to N_DISCON_IND */
9549     N_npi_data_t *discon_data;          /* pointer to N_DISCON_IND data */
9550     int rc = 0;                         /* return code */
9551
9552 #ifdef TRACE
9553     printf( "TRACE: entering x25clear\n" );
9554 #endif /* TRACE */
9555
9556 #ifdef DEBUG
9557     /* printf( "x25clear(): checking last msg: %s\n", x25prim(x25lastmsg)); */
9558 #endif /* DEBUG */
9559
9560     /*
9561     * The following checks are used to ensure that we don't disconnect
9562     * or unbind twice - this seems to throw the NPI interface right out of
9563     * kilter.
9564     */
9565     switch(x25lastmsg) {
9566       case N_BIND_ACK:
9567       case N_CONN_CON:
9568       case N_CONN_REQ:
9569       case N_DATA_REQ:
9570       case N_DATA_IND:
9571         {
9572 #ifdef DEBUG
9573             /* printf("x25clear(): actively disconnecting\n"); */
9574 #endif /* DEBUG */
9575
9576                 discon_req = (N_discon_req_t *)malloc(NPI_MAX_CTL);
9577                 if (discon_req == NULL) {
9578                     perror("kermit x25clear(): discon_req malloc failed\n");
9579                     /* fallthrough, try to unbind the NPI anyway */
9580                 } else {
9581                     discon_req->PRIM_type = N_DISCON_REQ;
9582                     discon_req->DISCON_reason = 0;      /* not used by AIX */
9583                     discon_req->RES_length = 0;
9584                     discon_req->RES_offset = (ulong)(sizeof(N_discon_req_t));
9585                     discon_req->SEQ_number = x25seqno;  /* global */
9586
9587                     if (x25putmsg(ttyfd,
9588                                   (N_npi_ctl_t*)discon_req,
9589                                   (N_npi_data_t*)NULL,
9590                                   0,
9591                                   &put_flags
9592                                   ) < 0) {
9593                         perror("x25putmsg failed in x25clear()");
9594                     }
9595                     discon_ind = (N_discon_ind_t *)malloc(NPI_MAX_CTL);
9596                     discon_data = (N_npi_data_t *)malloc(NPI_MAX_DATA);
9597                     if((discon_ind == NULL) || (discon_data == NULL)) {
9598                         perror("x25clear(): discon_ind malloc failed\n");
9599                         /* fallthrough, try to unbind the NPI anyway */
9600                     } else {
9601                         if(x25getmsg(ttyfd,
9602                                      (N_npi_ctl_t*)discon_ind,
9603                                      NPI_MAX_CTL,
9604                                      (N_npi_data_t*)discon_data,
9605                                      NPI_MAX_DATA,
9606                                      &get_flags,
9607                                      N_OK_ACK
9608                                      ) < 0 ) {
9609                             perror("x25getmsg failed in x25clear()");
9610                             /* fallthrough, try to unbind the NPI anyway */
9611                         }
9612                     }
9613                 }
9614                 break;
9615             }
9616     }
9617
9618     if (x25lastmsg != N_UNBIND_REQ) {
9619         rc = x25unbind(ttyfd);
9620     }
9621
9622 #ifdef TRACE
9623     printf( "TRACE: leaving x25clear\n" );
9624 #endif /* TRACE */
9625
9626     return(rc);
9627 }
9628
9629 #ifdef DEBUG
9630 /*
9631  * only for debugging
9632  *
9633  * turn the internal representation of a datablock into something
9634  * half-way readable. Because the length is known, we can print
9635  * the string including null's etc (important, because the first(!)
9636  * byte of an X121 address is a null! (X121 addr == 0 + X25 addr)
9637  */
9638 x25dump_data(char *addr, ulong offset, ulong length) {
9639     char *ptr = addr + offset;
9640     ulong i = length;
9641     /* allocate enough memory for all unprintable chars */
9642     char *buf = (char *)malloc( length * 4 );
9643     char *bptr = buf;   /* pointer to current place in the print buffer */
9644
9645     while (i > 0) {
9646         if (isprint(*ptr)) {
9647             *bptr++ = *ptr;
9648         } else {
9649             *bptr++ = '[';
9650             strcpy(bptr,ckctox(*ptr,1)); bptr += 2;
9651             *bptr++ = ']';
9652         }
9653         ptr++;
9654         i--;
9655     }
9656     if (length > 0) {
9657         *bptr = '\0';
9658         printf( "%s", buf );
9659     }
9660     printf( " (%d+%d)\n", offset, length );
9661
9662     if (buf) { free(buf); buf = NULL; }
9663     return;
9664 }
9665
9666 /*
9667  * only for debugging
9668  * print as much useful information about a packet as possible
9669  */
9670 x25dump_prim(primitive)    N_npi_ctl_t *primitive; {
9671     printf("Primitive");
9672     switch (primitive->PRIM_type) {
9673       case N_BIND_ACK:
9674         printf( "\tN_BIND_ACK\n\taddress:\t" );
9675         x25dump_data( (char *)primitive,
9676                      primitive->bind_ack.ADDR_offset,
9677                      primitive->bind_ack.ADDR_length );
9678         printf( "\tproto id:\t" );
9679         x25dump_data( (char *)primitive,
9680                      primitive->bind_ack.PROTOID_offset,
9681                      primitive->bind_ack.PROTOID_length );
9682         printf( "\tconnind:\t%d\n\ttoken:\t\t%d\n",
9683                primitive->bind_ack.CONIND_number,
9684                primitive->bind_ack.TOKEN_value );
9685         break;
9686
9687       case N_BIND_REQ:
9688         printf( "\tN_BIND_REQ\n\taddress:\t" );
9689         x25dump_data( (char *)primitive,
9690                      primitive->bind_req.ADDR_offset,
9691                      primitive->bind_req.ADDR_length );
9692         printf( "\tproto id:\t" );
9693         x25dump_data( (char *)primitive,
9694                      primitive->bind_req.PROTOID_offset,
9695                      primitive->bind_req.PROTOID_length );
9696         printf( "\tconnind:\t%d\n\tflags:\t\t%d\n",
9697                primitive->bind_req.CONIND_number,
9698                primitive->bind_req.BIND_flags );
9699         break;
9700
9701       case N_CONN_CON:
9702         printf( "\tN_CONN_CON\n" );
9703         printf( "\tRES\t\t" );
9704         x25dump_data( (char *)primitive,
9705                      primitive->conn_con.RES_offset,
9706                      primitive->conn_con.RES_length );
9707         printf( "\tflags:\t%d\n", primitive->conn_con.CONN_flags );
9708         break;
9709
9710       case N_CONN_IND:
9711         printf( "\tN_CONN_IND\n" );
9712         printf( "\tsource:\t\t" );
9713         x25dump_data( (char *)primitive,
9714                      primitive->conn_ind.SRC_offset,
9715                      primitive->conn_ind.SRC_length );
9716         printf( "\tdestination:\t" );
9717         x25dump_data( (char *)primitive,
9718                      primitive->conn_ind.DEST_offset,
9719                      primitive->conn_ind.DEST_length );
9720         printf( "\tSEQ_number:\t%d\n", primitive->conn_ind.SEQ_number );
9721         printf( "\tflags:\t%d\n", primitive->conn_ind.CONN_flags );
9722         break;
9723
9724       case N_CONN_REQ:
9725         printf( "\tN_CONN_REQ\n\tdestination:\t" );
9726         x25dump_data( (char *)primitive,
9727                      primitive->conn_req.DEST_offset,
9728                      primitive->conn_req.DEST_length );
9729         printf( "\tflags:\t%d\n", primitive->conn_req.CONN_flags );
9730         break;
9731
9732       case N_CONN_RES:
9733         printf( "\tN_CONN_RES\n" );
9734         printf( "\tTOKEN_value\t%d\n", primitive->conn_res.TOKEN_value );
9735         printf( "\tSEQ_number\t%d\n", primitive->conn_res.SEQ_number );
9736         printf( "\tCONN_flags\t%d\n", primitive->conn_res.CONN_flags );
9737         printf( "\tRES\t\t" );
9738         x25dump_data( (char *)primitive,
9739                      primitive->conn_res.RES_offset,
9740                      primitive->conn_res.RES_length );
9741         break;
9742
9743       case N_DATACK_IND:
9744         printf( "\tN_DATACK_IND\n" );
9745         break;
9746
9747       case N_DATACK_REQ:
9748         printf( "\tN_DATACK_REQ\n" );
9749         printf( "\tflags:\t%d\n", primitive->data_req.DATA_xfer_flags );
9750         break;
9751
9752       case N_DATA_IND:
9753         printf( "\tN_DATA_IND\n" );
9754         printf( "\tflags:\t%d\n", primitive->data_ind.DATA_xfer_flags );
9755         break;
9756
9757       case N_DATA_REQ:
9758         printf( "\tN_DATA_REQ\n" );
9759         break;
9760
9761       case N_DISCON_IND:
9762         printf( "\tN_DISCON_IND\n" );
9763         printf( "\torigin:\t%d\n", primitive->discon_ind.DISCON_orig );
9764         printf( "\treason:\t\t%d\n", primitive->discon_ind.DISCON_reason );
9765         printf( "\tseq no:\t\t%d\n", primitive->discon_ind.SEQ_number );
9766         printf( "\tRES:\t" );
9767         x25dump_data( (char *)primitive,
9768                      primitive->discon_ind.RES_offset,
9769                      primitive->discon_ind.RES_length );
9770         break;
9771
9772       case N_DISCON_REQ:
9773         printf( "\tN_DISCON_REQ\n" );
9774         printf( "\tDISCON_reason:\t%d\n",
9775                primitive->discon_req.DISCON_reason );
9776         printf( "\tRES:\t" );
9777         x25dump_data( (char *)primitive,
9778                      primitive->discon_req.RES_offset,
9779                      primitive->discon_req.RES_length );
9780         printf( "\tSEQ_number:\t%d\n", primitive->discon_req.SEQ_number );
9781         break;
9782
9783       case N_ERROR_ACK:
9784         printf( "\tN_ERROR_ACK\n" );
9785         printf( "\tCaused by:\t%s\n",
9786                x25prim( primitive->error_ack.ERROR_prim ) );
9787         printf( "\tNPI error:\t%s\n",
9788                x25err( primitive->error_ack.NPI_error ));
9789         errno = primitive->error_ack.UNIX_error;
9790         perror( "\t" );
9791         break;
9792
9793       case N_EXDATA_IND:
9794         printf( "\tN_EXDATA_ACK\n" );
9795         break;
9796
9797       case N_EXDATA_REQ:
9798         printf( "\tN_EXDATA_REQ\n" );
9799         break;
9800
9801       case N_INFO_ACK:
9802         printf( "\tN_INFO_ACK\n" );
9803         printf( "\tNSDU size:\t%d\n", primitive->info_ack.NSDU_size );
9804         printf( "\tENSDU size:\t%d\n", primitive->info_ack.ENSDU_size );
9805         printf( "\tCDATA size:\t%d\n", primitive->info_ack.CDATA_size );
9806         printf( "\tDDATA size:\t%d\n", primitive->info_ack.DDATA_size );
9807         printf( "\tADDR size:\t%d\n", primitive->info_ack.ADDR_size );
9808         printf( "\tNIDU size:\t%d\n", primitive->info_ack.NIDU_size );
9809         break;
9810
9811       case N_INFO_REQ:
9812         printf( "\tN_INFO_REQ\n" );
9813         break;
9814
9815       case N_OK_ACK:
9816         printf( "\tN_OK_ACK\n" );
9817         break;
9818
9819       case N_OPTMGMT_REQ:
9820         printf( "\tN_OPTMGMT_REQ\n" );
9821         break;
9822
9823       case N_RESET_CON:
9824         printf( "\tN_RESET_CON\n" );
9825         break;
9826
9827       case N_RESET_IND:
9828         printf( "\tN_RESET_IND\n" );
9829         printf( "\treason:\t\t%d\n", primitive->reset_ind.RESET_reason );
9830         printf( "\torigin:\t\t%d\n", primitive->reset_ind.RESET_orig );
9831         break;
9832
9833       case N_RESET_REQ:
9834         printf( "\tN_RESET_REQ\n" );
9835         printf( "\treason:\t\t%d\n", primitive->reset_req.RESET_reason );
9836         break;
9837
9838       case N_RESET_RES:
9839         printf( "\tN_RESET_RES\n" );
9840         break;
9841
9842       case N_UDERROR_IND:
9843         printf( "\tN_UDERROR_IND\n" );
9844         break;
9845
9846       case N_UNBIND_REQ:
9847         printf( "\tN_UNBIND_REQ\n" );
9848         break;
9849
9850       case N_UNITDATA_REQ:
9851         printf( "\tN_UNITDATA_REQ\n" );
9852         break;
9853
9854       case N_UNITDATA_IND:
9855         printf( "\tN_UNITDATA_IND\n" );
9856         break;
9857
9858       default:
9859         (void) printf( "Unknown NPI error %d", primitive->PRIM_type );
9860         return 0;
9861     }
9862 }
9863 #endif /* DEBUG */
9864
9865 /* it looks like signal handling is not needed with streams! */
9866 /* x25oobh()    - handle SIGURG signals - take from isode ? */
9867
9868 #endif /* IBMX25 */
9869
9870 #ifndef NOHTTP
9871 /*
9872   Which time.h files to include... See ckcdeb.h for defaults.
9873   Note that 0, 1, 2, or all 3 of these can be included according to
9874   the symbol definitions.
9875 */
9876 #ifndef NOTIMEH
9877 #ifdef TIMEH
9878 #include <time.h>
9879 #endif /* TIMEH */
9880 #endif /* NOTIMEH */
9881
9882 #ifndef NOSYSTIMEH
9883 #ifdef SYSTIMEH
9884 #include <sys/time.h>
9885 #endif /* SYSTIMEH */
9886 #endif /* NOSYSTIMEH */
9887
9888 #ifndef NOSYSTIMEBH
9889 #ifdef SYSTIMEBH
9890 #include <sys/timeb.h>
9891 #endif /* SYSTIMEBH */
9892 #endif /* NOSYSTIMEBH */
9893
9894 #ifndef TIMEH
9895 #ifndef SYSTIMEH
9896 #ifndef SYSTIMEBH
9897 #ifdef Plan9
9898 #include <sys/time.h>
9899 #else
9900 #ifdef AIX41
9901 #include <time.h>
9902 #else
9903 #ifdef SUNOS4
9904 #include <sys/time.h>
9905 #else
9906 #ifdef SYSTIMEH
9907 #include <sys/time.h>
9908 #else
9909 #ifdef POSIX
9910 #include <posix/time.h>
9911 #else
9912 #ifdef CLIX
9913 #include <sys/time.h>
9914 #else
9915 #ifdef OS2
9916 #include <time.h>
9917 #else
9918 #include <time.h>
9919 /* #include <utime.h> */
9920 #endif /* OS2 */
9921 #endif /* CLIX */
9922 #endif /* POSIX */
9923 #endif /* SYSTIMEH */
9924 #endif /* SUNOS4 */
9925 #endif /* AIX41 */
9926 #endif /* Plan9 */
9927 #endif
9928 #endif
9929 #endif
9930
9931 #ifdef OS2
9932 #include <sys/utime.h>
9933 #ifdef NT
9934 #define utimbuf _utimbuf
9935 #endif /* NT */
9936 #define utime   _utime
9937 #else
9938 #ifdef SYSUTIMEH                        /* <sys/utime.h> if requested,  */
9939 #include <sys/utime.h>                  /* for extra fields required by */
9940 #else                                   /* 88Open spec. */
9941 #ifdef UTIMEH                           /* or <utime.h> if requested */
9942 #include <utime.h>                      /* (SVR4, POSIX) */
9943 #define SYSUTIMEH                       /* Use this for both cases. */
9944 #endif /* UTIMEH */
9945 #endif /* SYSUTIMEH */
9946 #endif /* OS2 */
9947
9948 #ifdef VMS                              /* SMS 2007/02/15 */
9949 #include "ckvrtl.h"
9950 #endif /* def VMS */
9951
9952 #ifndef HTTP_VERSION
9953 #define HTTP_VERSION "HTTP/1.1"
9954 #endif /* HTTP_VERSION */
9955
9956 #ifdef CMDATE2TM
9957 time_t
9958 #ifdef CK_ANSIC
9959 http_date(char * date)
9960 #else
9961 http_date(date) char * date;
9962 #endif /* CK_ANSIC */
9963 /* http_date */ {
9964     /* HTTP dates are of the form:  "Sun, 06 Oct 1997 20:11:47 GMT" */
9965     /* There are two older formats which we are required to parse
9966      * that we currently do not:
9967      *
9968      * RFC 850:   "Sunday, 06-Oct-97 20:11:47 GMT"
9969      * asctime(): "Sun Nov  6 20:11:47 1997"
9970      *
9971      * However, it is required that all dates be sent in the form we
9972      * do accept.  The other two formats are for compatibility with
9973      * really old servers.
9974      */
9975     extern char cmdatebuf[18];
9976     struct tm t_tm;
9977     time_t t;
9978     char ldate[32];
9979     int j;
9980
9981     j = ckindex(",",date,0,0,0);
9982     ckstrncpy(ldate,&date[j+1],25);
9983
9984     {   /*
9985            cmcvtate() date changed to return a string pointer.
9986            fdc, 12 Aug 2001.
9987         */
9988         char * dp;
9989         dp = (char *)cmcvtdate(ldate,0); /* Convert to normal form */
9990         if (!dp)
9991           return(0);
9992         t_tm = *cmdate2tm(dp,1);
9993     }
9994 /*
9995   From Lucas Hart, 5 Dec 2001:
9996   "On the systems to which I have access (SunOS 4.1.1, Solaris 8, and Tru64),
9997   setting tm_isdst to -1 maintains the correct timezone offsets, i.e., writes
9998   the specified (GMT) time if the buffer size is 21, or the contemporaneous
9999   localtime if the buffer size is 25.  Perhaps tm_isdst should be set in
10000   cmdate2tm(), rather than only in http_date."
10001 */
10002 #ifndef NOTM_ISDST                      /* For platforms where */
10003     t_tm.tm_isdst = -1;                 /* tm_isdst doesn't exist. */
10004 #endif /* NOTM_ISDST */
10005
10006     t = mktime(&t_tm);                  /* NOT PORTABLE */
10007
10008 #ifdef XX_TIMEZONE
10009     t -= _timezone;
10010 #endif /* XX_TIMEZONE */
10011
10012     return(t);
10013 }
10014 #endif /* CMDATE2TM */
10015
10016 char *
10017 http_now() {
10018     static char nowstr[32];
10019 #ifdef CMDATE2TM
10020     struct tm  *gmt;
10021     time_t ltime;                       /* NOT PORTABLE */
10022
10023     time(&ltime);
10024
10025     gmt = gmtime(&ltime);               /* PROBABLY NOT PORTABLE */
10026     strftime(nowstr,32,"%a, %d %b %Y %H:%M:%S GMT",gmt); /* NOT PORTABLE */
10027     /* not only is it not portable but it's locale-dependent */
10028 #else
10029 /*
10030   This is hopeless.  First of all, it seems that HTTP wants Day and Month
10031   NAMES?  In English?  Whose idea was that?  Even worse, the date/time must be
10032   expressed in Zulu (UTC (GMT)), and converting from local time to GMT is a
10033   nightmare.  Every platform does it differently, if at all -- even if we
10034   restrict ourselves to UNIX.  For example (quoting from recent C-Kermit edit
10035   history), "Fixed a longstanding bug in the BSDI version, in which incoming
10036   file dates were set in GMT rather than local time.  It seems in 4.4BSD,
10037   localtime() does not return the local time, but rather Zero Meridian (Zulu)
10038   time (GMT), and must be adjusted by the tm_gmtoff value."  Swell.  For
10039   greater appreciation of the scope of the problem, just take a look at the
10040   time-related #ifdefs in ckutio.c.  The only right way to do this is to add
10041   our own portable API for converting between local time and GMT/UTC/Zulu
10042   that shields us not only from UNIXisms like time_t and struct tm, but also
10043   the unbelievable amount of differences in time-related APIs -- e.g. is
10044   "timezone" an external variable or a function; which header file(s) do we
10045   include, etc etc etc.  It's a major project.
10046 */
10047     int x;
10048     x = cmcvtdate("",1);
10049
10050 Evidently this code is not used -- if it is, it must be fixed to use
10051 new (aug 2001) cmcvtdate() calling conventions.
10052
10053     if (x < 0)
10054       return("");
10055 /*  yyyymmdd hh:mm:ss */
10056 /*  01234567890123456 */
10057     nowstr[0]  = 'X';                   /* 1st letter of day */
10058     nowstr[1]  = 'x';                   /* 2nd letter of day */
10059     nowstr[2]  = 'x';                   /* 3rd letter of day */
10060     nowstr[3]  = ',';
10061     nowstr[4]  = ' ';
10062     nowstr[5]  = cmdate[6];
10063     nowstr[6]  = cmdate[7];
10064     nowstr[7]  = ' ';
10065     nowstr[8]  = ' ';                   /* first letter of month */
10066     nowstr[9]  = ' ';                   /* second letter of month */
10067     nowstr[10] = ' ';                   /* third letter of month */
10068     nowstr[11] = ' ';
10069     nowstr[12] = cmdate[0];
10070     nowstr[13] = cmdate[1];
10071     nowstr[14] = cmdate[2];
10072     nowstr[15] = cmdate[3];
10073     nowstr[16] = ' ';
10074     nowstr[17] = cmdate[9];
10075     nowstr[18] = cmdate[10];
10076     nowstr[19] = cmdate[11];
10077     nowstr[20] = cmdate[12];
10078     nowstr[21] = cmdate[13];
10079     nowstr[22] = cmdate[14];
10080     nowstr[23] = cmdate[15];
10081     nowstr[24] = cmdate[16];
10082     nowstr[25] = ' ';
10083     nowstr[26] = 'G';
10084     nowstr[27] = 'M';
10085     nowstr[28] = 'T';
10086     nowstr[29] = '\0';
10087 #endif /* CMDATE2TM */
10088     return(nowstr);
10089 }
10090
10091 #ifndef OS2
10092 #ifndef CK_AUTHENTICATION
10093 /* from ckuusr.h, which this module normally doesn't include */
10094 _PROTOTYP( int dclarray, (char, int) );
10095 #endif /* CK_AUTHENTICATION */
10096 #endif /* OS2 */
10097 /*
10098   Assign http response pairs to given array.
10099   For best results, response pairs should contain no spaces.
10100
10101   Call with:
10102     resp  =  pointer to response list.
10103     n     =  size of response list.
10104     array =  array letter.
10105   Returns:
10106     0 on failure.
10107     >= 1, size of array, on success.
10108 */
10109 static int
10110 #ifdef CK_ANSIC
10111 http_mkarray(char ** resp, int n, char array)
10112 #else
10113 http_mkarray(resp, n, array) char ** resp; int n; char array;
10114 #endif /* CK_ANSIC */
10115 {
10116 #ifndef NOSPL
10117     int i, x;
10118     char ** ap;
10119     extern char ** a_ptr[];
10120     extern int a_dim[];
10121
10122     if (!array || n <= 0)
10123       return(0);
10124     if ((x = dclarray(array,n)) < 0) {
10125         printf("?Array declaration failure\n");
10126         return(-9);
10127     }
10128     /* Note: argument array is 0-based but Kermit array is 1-based */
10129     ap = a_ptr[x];
10130     ap[0] = NULL;                       /* 0th element is empty */
10131     for (i = 1; i <= n; i++) {
10132         ap[i] = resp[i-1];              /* If resp elements were malloc'd */
10133         resp[i-1] = NULL;
10134     }
10135     a_dim[x] = n;
10136     return(n);
10137 #else
10138     return(0);
10139 #endif /* NOSPL */
10140 }
10141
10142 #define HTTPHEADCNT 64
10143 int
10144 http_get_chunk_len()
10145 {
10146     int len = 0;
10147     int i = 0, j = -1;
10148     char buf[24];
10149     int ch;
10150
10151     while ((ch = http_inc(0)) >= 0 && i < 24) {
10152         buf[i] = ch;
10153         if ( buf[i] == ';' )            /* Find chunk-extension (if any) */
10154             j = i;
10155         if ( buf[i] == 10 ) {           /* found end of line */
10156             if (i > 0 && buf[i-1] == 13)
10157                 i--;
10158             buf[i] = '\0';
10159             break;
10160         }
10161         i++;
10162     }
10163     if ( i < 24 ) {                     /* buf now contains len in Hex */
10164         len = hextoulong(buf, j == -1 ? i : j-1);
10165     }
10166
10167     return(len);
10168 }
10169
10170 int
10171 http_isconnected()
10172 {
10173     return(httpfd != -1);
10174 }
10175
10176 char *
10177 http_host()
10178 {
10179     return(httpfd != -1 ? http_host_port : "");
10180 }
10181
10182 char *
10183 http_security()
10184 {
10185     if ( httpfd == -1 )
10186         return("NULL");
10187 #ifdef CK_SSL
10188     if (tls_http_active_flag) {
10189         SSL_CIPHER * cipher;
10190         const char *cipher_list;
10191         static char buf[128];
10192         buf[0] = NUL;
10193         cipher = SSL_get_current_cipher(tls_http_con);
10194         cipher_list = SSL_CIPHER_get_name(cipher);
10195         SSL_CIPHER_description(cipher,buf,sizeof(buf));
10196         return(buf);
10197     }
10198 #endif /* CK_SSL */
10199     return("NULL");
10200 }
10201
10202 int
10203 http_reopen()
10204 {
10205     int rc = 0;
10206     char * s = NULL;                    /* strdup is not portable */
10207     if ( tcp_http_proxy ) {
10208         char * p;
10209         makestr(&s,(char *)http_host_port);
10210         p = s;
10211         while (*p != '\0' && *p != ':') p++; /* Look for colon */
10212         if (*p == ':') {                     /* Have a colon */
10213             *p++ = '\0';                     /* Get service name or number */
10214         } else {
10215             p="http";
10216         }
10217         rc = http_open(s,p,http_ssl,NULL,0,http_agent);
10218     } else {
10219         makestr(&s,(char *)http_ip);
10220         rc = http_open(s,ckuitoa(http_port),http_ssl,NULL,0,http_agent);
10221     }
10222     free(s);
10223     return(rc);
10224 }
10225
10226
10227 int
10228 #ifdef CK_ANSIC
10229 http_open(char * hostname, char * svcname, int use_ssl, char * rdns_name,
10230           int rdns_len, char * agent)
10231 #else /* CK_ANSIC */
10232 http_open(hostname, svcname, use_ssl, rdns_name, rdns_len, agent)
10233     char * hostname;
10234     char * svcname;
10235     int    use_ssl;
10236     char * rdns_name;
10237     int    rdns_len;
10238     char * agent;
10239 #endif /* CK_ANSIC */
10240 {
10241     char namecopy[NAMECPYL];
10242     char *p;
10243     int i, x, dns = 0;
10244 #ifdef TCPSOCKET
10245     int isconnect = 0;
10246 #ifdef SO_OOBINLINE
10247     int on = 1;
10248 #endif /* SO_OOBINLINE */
10249     struct servent *service=NULL;
10250     struct hostent *host=NULL;
10251     struct sockaddr_in r_addr;
10252     struct sockaddr_in sin;
10253     struct sockaddr_in l_addr;
10254     GSOCKNAME_T l_slen;
10255 #ifdef EXCELAN
10256     struct sockaddr_in send_socket;
10257 #endif /* EXCELAN */
10258
10259 #ifdef INADDRX
10260 /* inet_addr() is of type struct in_addr */
10261 #ifdef datageneral
10262     extern struct in_addr inet_addr();
10263 #else
10264 #ifdef HPUX5WINTCP
10265     extern struct in_addr inet_addr();
10266 #endif /* HPUX5WINTCP */
10267 #endif /* datageneral */
10268     struct in_addr iax;
10269 #else
10270 #ifdef INADDR_NONE
10271     struct in_addr iax;
10272 #else /* INADDR_NONE */
10273     long iax;
10274 #endif /* INADDR_NONE */
10275 #endif /* INADDRX */
10276
10277     if ( rdns_name == NULL || rdns_len < 0 )
10278         rdns_len = 0;
10279
10280     *http_ip = '\0';                     /* Initialize IP address string */
10281     namecopy[0] = '\0';
10282
10283 #ifdef DEBUG
10284     if (deblog) {
10285         debug(F110,"http_open hostname",hostname,0);
10286         debug(F110,"http_open svcname",svcname,0);
10287     }
10288 #endif /* DEBUG */
10289     if (!hostname) hostname = "";
10290     if (!svcname) svcname = "";
10291     if (!*hostname || !*svcname) return(-1);
10292
10293     
10294     service = ckgetservice(hostname,svcname,http_ip,20);
10295
10296     if (service == NULL) {
10297         if ( !quiet )
10298             printf("?Invalid service: %s\r\n",svcname);
10299         return(-1);
10300     }
10301
10302     /* For HTTP connections we must preserve the original hostname and */
10303     /* service requested so we can include them in the Host header.    */
10304     ckmakmsg(http_host_port,sizeof(http_host_port),hostname,":",
10305               ckuitoa(ntohs(service->s_port)),NULL);
10306     http_port = ntohs(service->s_port);
10307     http_ssl = use_ssl;
10308     debug(F111,"http_open",http_host_port,http_port);
10309
10310     /* 'http_ip' contains the IP address to which we want to connect        */
10311     /* 'svcnam'   contains the service name                                 */
10312     /* 'service->s_port' contains the port number in network byte order     */
10313
10314     /* If we are using an http proxy, we need to create a buffer containing */
10315     /*   hostname:port-number                                               */
10316     /* to pass to the http_connect() function.  Then we need to replace     */
10317     /* 'namecopy' with the name of the proxy server and the service->s_port */
10318     /* with the port number of the proxy (default port 80).                 */
10319
10320     if ( tcp_http_proxy ) {
10321
10322         ckmakmsg(proxycopy,sizeof(proxycopy),hostname,":",
10323                  ckuitoa(ntohs(service->s_port)),NULL);
10324         ckstrncpy(namecopy,tcp_http_proxy,NAMECPYL);
10325
10326         p = namecopy;                       /* Was a service requested? */
10327         while (*p != '\0' && *p != ':') p++; /* Look for colon */
10328         if (*p == ':') {                    /* Have a colon */
10329             debug(F110,"http_open name has colon",namecopy,0);
10330             *p++ = '\0';                    /* Get service name or number */
10331         } else {
10332             strcpy(++p,"http");
10333         }
10334
10335         service = ckgetservice(namecopy,p,http_ip,20);
10336         if (!service) {
10337             fprintf(stderr, "Can't find port for service %s\n", p);
10338 #ifdef TGVORWIN
10339             debug(F101,"http_open can't get service for proxy","",socket_errno);
10340 #else
10341             debug(F101,"http_open can't get service for proxy","",errno);
10342 #endif /* TGVORWIN */
10343             errno = 0;                  /* (rather than mislead) */
10344             return(-1);
10345         }
10346
10347         /* copy the proxyname and remove the service if any so we can use 
10348          * it as the hostname 
10349          */
10350         ckstrncpy(namecopy,tcp_http_proxy,NAMECPYL);
10351         p = namecopy;                       /* Was a service requested? */
10352         while (*p != '\0' && *p != ':') p++; /* Look for colon */
10353         if (*p == ':') {                    /* Have a colon */
10354             *p = '\0';                      /* terminate string */
10355         }        
10356         hostname = namecopy;                /* use proxy as hostname */
10357     }
10358
10359     /* Set up socket structure and get host address */
10360     bzero((char *)&r_addr, sizeof(r_addr));
10361     debug(F100,"http_open bzero ok","",0);
10362
10363 #ifdef INADDR_NONE
10364     debug(F101,"http_open INADDR_NONE defined","",INADDR_NONE);
10365 #else /* INADDR_NONE */
10366     debug(F100,"http_open INADDR_NONE not defined","",0);
10367 #endif /* INADDR_NONE */
10368 #ifdef INADDRX
10369     debug(F100,"http_open INADDRX defined","",0);
10370 #else /* INADDRX */
10371     debug(F100,"http_open INADDRX not defined","",0);
10372 #endif /* INADDRX */
10373
10374 #ifndef NOMHHOST
10375 #ifdef INADDRX
10376     iax = inet_addr(http_ip[0]?http_ip:hostname);
10377     debug(F111,"http_open inet_addr",http_ip[0]?http_ip:hostname,iax.s_addr);
10378 #else /* INADDRX */
10379 #ifdef INADDR_NONE
10380     iax.s_addr = inet_addr(http_ip[0]?http_ip:hostname);
10381     debug(F111,"http_open inet_addr",http_ip[0]?http_ip:hostname,iax.s_addr);
10382 #else /* INADDR_NONE */
10383 #ifndef datageneral
10384     iax = (unsigned int) inet_addr(http_ip[0]?http_ip:hostname);
10385 #else
10386     iax = -1L;
10387 #endif /* datageneral */
10388     debug(F111,"http_open inet_addr",http_ip[0]?http_ip:hostname,iax);
10389 #endif /* INADDR_NONE */
10390 #endif /* INADDRX */
10391
10392     dns = 0;
10393     if (
10394 #ifdef INADDR_NONE
10395 /* This might give warnings on 64-bit platforms but they should be harmless */
10396 /* because INADDR_NONE should be all 1's anyway, thus the OR part is */
10397 /* probably superfluous -- not sure why it's even there, maybe it should be */
10398 /* removed. */
10399         iax.s_addr == INADDR_NONE /* || iax.s_addr == (unsigned long) -1L */
10400 #else /* INADDR_NONE */
10401         iax == -1
10402 #endif /* INADDR_NONE */
10403         ) {
10404         if (!quiet) {
10405             printf(" DNS Lookup... ");
10406             fflush(stdout);
10407         }
10408         if ((host = gethostbyname(http_ip[0] ? http_ip : hostname)) != NULL) {
10409             debug(F100,"http_open gethostbyname != NULL","",0);
10410             host = ck_copyhostent(host);
10411             dns = 1;                    /* Remember we performed dns lookup */
10412             r_addr.sin_family = host->h_addrtype;
10413             if (tcp_rdns && host->h_name && host->h_name[0] && (rdns_len > 0)
10414                  && (tcp_http_proxy == NULL)
10415                  )
10416                 ckmakmsg(rdns_name,rdns_len,host->h_name,":",svcname,NULL);
10417
10418 #ifdef HADDRLIST
10419 #ifdef h_addr
10420             /* This is for trying multiple IP addresses - see <netdb.h> */
10421             if (!(host->h_addr_list))
10422               return(-1);
10423             bcopy(host->h_addr_list[0],
10424                   (caddr_t)&r_addr.sin_addr,
10425                   host->h_length
10426                   );
10427 #else
10428             bcopy(host->h_addr, (caddr_t)&r_addr.sin_addr, host->h_length);
10429 #endif /* h_addr */
10430 #else  /* HADDRLIST */
10431             bcopy(host->h_addr, (caddr_t)&r_addr.sin_addr, host->h_length);
10432 #endif /* HADDRLIST */
10433 #ifdef COMMENT
10434 #ifndef EXCELAN
10435             debug(F111,"BCOPY","host->h_addr",host->h_addr);
10436 #endif /* EXCELAN */
10437             debug(F111,"BCOPY"," (caddr_t)&r_addr.sin_addr",
10438                   (caddr_t)&r_addr.sin_addr);
10439             debug(F111,"BCOPY"," r_addr.sin_addr.s_addr",
10440                   r_addr.sin_addr.s_addr);
10441 #endif  /* COMMENT */
10442             debug(F111,"BCOPY","host->h_length",host->h_length);
10443         }
10444     }
10445 #endif /* NOMHHOST */
10446
10447     if (!dns) {
10448 #ifdef INADDRX
10449 /* inet_addr() is of type struct in_addr */
10450         struct in_addr ina;
10451         unsigned long uu;
10452         debug(F100,"http_open gethostbyname == NULL: INADDRX","",0);
10453         ina = inet_addr(http_ip[0]?http_ip:hostname);
10454         uu = *(unsigned int *)&ina;
10455 #else /* Not INADDRX */
10456 /* inet_addr() is unsigned long */
10457         unsigned long uu;
10458         debug(F100,"http_open gethostbyname == NULL: Not INADDRX","",0);
10459         uu = inet_addr(http_ip[0]?http_ip:hostname);
10460 #endif /* INADDRX */
10461         debug(F101,"http_open uu","",uu);
10462         if (
10463 #ifdef INADDR_NONE
10464             !(uu == INADDR_NONE || uu == (unsigned int) -1L)
10465 #else   /* INADDR_NONE */
10466             uu != ((unsigned long)-1)
10467 #endif /* INADDR_NONE */
10468             ) {
10469             r_addr.sin_addr.s_addr = uu;
10470             r_addr.sin_family = AF_INET;
10471         } else {
10472 #ifdef VMS
10473             fprintf(stdout, "\r\n");    /* complete any previous message */
10474 #endif /* VMS */
10475             fprintf(stderr, "Can't get address for %s\n",
10476                      http_ip[0]?http_ip:hostname);
10477 #ifdef TGVORWIN
10478             debug(F101,"http_open can't get address","",socket_errno);
10479 #else
10480             debug(F101,"http_open can't get address","",errno);
10481 #endif /* TGVORWIN */
10482             errno = 0;                  /* Rather than mislead */
10483             return(-1);
10484         }
10485     }
10486
10487     /* Get a file descriptor for the connection. */
10488
10489     r_addr.sin_port = service->s_port;
10490     ckstrncpy(http_ip,(char *)inet_ntoa(r_addr.sin_addr),20);
10491     debug(F110,"http_open trying",http_ip,0);
10492     if (!quiet && *http_ip) {
10493         printf(" Trying %s... ", http_ip);
10494         fflush(stdout);
10495     }
10496
10497     /* Loop to try additional IP addresses, if any. */
10498
10499     do {
10500 #ifdef EXCELAN
10501         send_socket.sin_family = AF_INET;
10502         send_socket.sin_addr.s_addr = 0;
10503         send_socket.sin_port = 0;
10504         if ((httpfd = socket(SOCK_STREAM, (struct sockproto *)0,
10505                             &send_socket, SO_REUSEADDR)) < 0)
10506 #else  /* EXCELAN */
10507         if ((httpfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
10508 #endif /* EXCELAN */
10509             {
10510 #ifdef EXCELAN
10511                 experror("TCP socket error");
10512 #else
10513 #ifdef TGVORWIN
10514 #ifdef OLD_TWG
10515                 errno = socket_errno;
10516 #endif /* OLD_TWG */
10517                 socket_perror("TCP socket error");
10518                 debug(F101,"http_open socket error","",socket_errno);
10519 #else
10520                 perror("TCP socket error");
10521                 debug(F101,"http_open socket error","",errno);
10522 #endif /* TGVORWIN */
10523 #endif /* EXCELAN */
10524                 return (-1);
10525             }
10526         errno = 0;
10527
10528        /* If a specific TCP address on the local host is desired we */
10529        /* must bind it to the socket.                               */
10530 #ifndef datageneral
10531          if (tcp_address) {
10532              int s_errno;
10533
10534              debug(F110,"http_open binding socket to",tcp_address,0);
10535              bzero((char *)&sin,sizeof(sin));
10536              sin.sin_family = AF_INET;
10537 #ifdef INADDRX
10538              inaddrx = inet_addr(tcp_address);
10539              sin.sin_addr.s_addr = *(unsigned long *)&inaddrx;
10540 #else
10541              sin.sin_addr.s_addr = inet_addr(tcp_address);
10542 #endif /* INADDRX */
10543              sin.sin_port = 0;
10544              if (bind(httpfd, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
10545                  s_errno = socket_errno; /* Save error code */
10546 #ifdef TCPIPLIB
10547                  socket_close(httpfd);
10548 #else /* TCPIPLIB */
10549                  close(httpfd);
10550 #endif /* TCPIPLIB */
10551                  httpfd = -1;
10552                  errno = s_errno;       /* and report this error */
10553                  debug(F101,"http_open bind errno","",errno);
10554                  return(-1);
10555              }
10556          }
10557 #endif /* datageneral */
10558
10559 /* Now connect to the socket on the other end. */
10560
10561 #ifdef EXCELAN
10562         if (connect(httpfd, &r_addr) < 0)
10563 #else
10564 #ifdef NT
10565           WSASafeToCancel = 1;
10566 #endif /* NT */
10567         if (connect(httpfd, (struct sockaddr *)&r_addr, sizeof(r_addr)) < 0)
10568 #endif /* EXCELAN */
10569           {
10570 #ifdef NT
10571               WSASafeToCancel = 0;
10572 #endif /* NT */
10573 #ifdef OS2
10574               i = socket_errno;
10575 #else /* OS2 */
10576 #ifdef TGVORWIN
10577               i = socket_errno;
10578 #else
10579               i = errno;                /* Save error code */
10580 #endif /* TGVORWIN */
10581 #endif /* OS2 */
10582 #ifdef HADDRLIST
10583 #ifdef h_addr
10584               if (host && host->h_addr_list && host->h_addr_list[1]) {
10585                   perror("");
10586                   host->h_addr_list++;
10587                   bcopy(host->h_addr_list[0],
10588                         (caddr_t)&r_addr.sin_addr,
10589                         host->h_length);
10590
10591                   ckstrncpy(http_ip,(char *)inet_ntoa(r_addr.sin_addr),20);
10592                   debug(F110,"http_open h_addr_list",http_ip,0);
10593                   if (!quiet && *http_ip) {
10594                       printf(" Trying %s... ", http_ip);
10595                       fflush(stdout);
10596                   }
10597 #ifdef TCPIPLIB
10598                   socket_close(httpfd); /* Close it. */
10599 #else
10600                   close(httpfd);
10601 #endif /* TCPIPLIB */
10602                   continue;
10603               }
10604 #endif /* h_addr */
10605 #endif  /* HADDRLIST */
10606               http_close();
10607               httpfd = -1;
10608               errno = i;                /* And report this error */
10609 #ifdef EXCELAN
10610               if (errno) experror("http_open connect");
10611 #else
10612 #ifdef TGVORWIN
10613               debug(F101,"http_open connect error","",socket_errno);
10614               /* if (errno) socket_perror("http_open connect"); */
10615 #ifdef OLD_TWG
10616               errno = socket_errno;
10617 #endif /* OLD_TWG */
10618               if (!quiet)
10619                 socket_perror("http_open connect");
10620 #else /* TGVORWIN */
10621               debug(F101,"http_open connect errno","",errno);
10622 #ifdef VMS
10623               if (!quiet)
10624                 perror("\r\nFailed");
10625 #else
10626               if (!quiet)
10627                 perror("Failed");
10628 #endif /* VMS */
10629 #ifdef DEC_TCPIP
10630               if (!quiet)
10631                 perror("http_open connect");
10632 #endif /* DEC_TCPIP */
10633 #ifdef CMU_TCPIP
10634               if (!quiet)
10635                 perror("http_open connect");
10636 #endif /* CMU_TCPIP */
10637 #endif /* TGVORWIN */
10638 #endif /* EXCELAN */
10639               return(-1);
10640           }
10641 #ifdef NT
10642         WSASafeToCancel = 0;
10643 #endif /* NT */
10644         isconnect = 1;
10645     } while (!isconnect);
10646
10647 #ifdef NON_BLOCK_IO
10648     on = 1;
10649     x = socket_ioctl(httpfd,FIONBIO,&on);
10650     debug(F101,"http_open FIONBIO","",x);
10651 #endif /* NON_BLOCK_IO */
10652
10653     /* We have succeeded in connecting to the HTTP PROXY.  So now we   */
10654     /* need to attempt to connect through the proxy to the actual host */
10655     /* If that is successful, we have to pretend that we made a direct */
10656     /* connection to the actual host.                                  */
10657
10658     if ( tcp_http_proxy ) {
10659 #ifdef OS2
10660         if (!agent) 
10661           agent = "Kermit 95";  /* Default user agent */
10662 #else
10663         if (!agent) 
10664           agent = "C-Kermit";
10665 #endif /* OS2 */
10666
10667         if (http_connect(httpfd,
10668                          tcp_http_proxy_agent ? tcp_http_proxy_agent : agent,
10669                          NULL,
10670                          tcp_http_proxy_user,
10671                          tcp_http_proxy_pwd,
10672                          0,
10673                          proxycopy
10674                          ) < 0) {
10675             http_close();
10676             return(-1);
10677         }
10678     }
10679
10680 #ifdef SO_OOBINLINE
10681     /* See note on SO_OOBINLINE in netopen() */
10682 #ifdef datageneral
10683     setsockopt(httpfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
10684 #else
10685 #ifdef BSD43
10686     setsockopt(httpfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
10687 #else
10688 #ifdef OSF1
10689     setsockopt(httpfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
10690 #else
10691 #ifdef POSIX
10692     setsockopt(httpfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
10693 #else
10694 #ifdef MOTSV88R4
10695     setsockopt(httpfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
10696 #else
10697 #ifdef SOLARIS
10698 /*
10699   Maybe this applies to all SVR4 versions, but the other (else) way has been
10700   compiling and working fine on all the others, so best not to change it.
10701 */
10702     setsockopt(httpfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
10703 #else
10704 #ifdef OSK
10705     setsockopt(httpfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
10706 #else
10707 #ifdef OS2
10708     {
10709         int rc;
10710         rc = setsockopt(httpfd,
10711                         SOL_SOCKET,
10712                         SO_OOBINLINE,
10713                         (char *) &on,
10714                         sizeof on
10715                         );
10716         debug(F111,"setsockopt SO_OOBINLINE",on ? "on" : "off" ,rc);
10717     }
10718 #else
10719 #ifdef VMS /* or, at least, VMS with gcc */
10720     setsockopt(httpfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
10721 #else
10722 #ifdef CLIX
10723     setsockopt(httpfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
10724 #else
10725     setsockopt(httpfd, SOL_SOCKET, SO_OOBINLINE, &on, sizeof on);
10726 #endif /* CLIX */
10727 #endif /* VMS */
10728 #endif /* OS2 */
10729 #endif /* OSK */
10730 #endif /* SOLARIS */
10731 #endif /* MOTSV88R4 */
10732 #endif /* POSIX */
10733 #endif /* BSD43 */
10734 #endif /* OSF1 */
10735 #endif /* datageneral */
10736 #endif /* SO_OOBINLINE */
10737
10738 #ifndef NOTCPOPTS
10739 #ifndef datageneral
10740 #ifdef SOL_SOCKET
10741 #ifdef TCP_NODELAY
10742     no_delay(ttyfd,tcp_nodelay);
10743 #endif /* TCP_NODELAY */
10744 #ifdef SO_KEEPALIVE
10745     keepalive(ttyfd,tcp_keepalive);
10746 #endif /* SO_KEEPALIVE */
10747 #ifdef SO_LINGER
10748     ck_linger(ttyfd,tcp_linger, tcp_linger_tmo);
10749 #endif /* SO_LINGER */
10750 #ifdef SO_SNDBUF
10751     sendbuf(ttyfd,tcp_sendbuf);
10752 #endif /* SO_SNDBUF */
10753 #ifdef SO_RCVBUF
10754     recvbuf(ttyfd,tcp_recvbuf);
10755 #endif /* SO_RCVBUF */
10756 #endif /* SOL_SOCKET */
10757 #endif /* datageneral */
10758 #endif /* NOTCPOPTS */
10759
10760 #ifndef datageneral
10761     /* Find out our own IP address. */
10762     /* We need the l_addr structure for [E]KLOGIN. */
10763     l_slen = sizeof(l_addr);
10764     bzero((char *)&l_addr, l_slen);
10765 #ifndef EXCELAN
10766     if (!getsockname(httpfd, (struct sockaddr *)&l_addr, &l_slen)) {
10767         char * s = (char *)inet_ntoa(l_addr.sin_addr);
10768         ckstrncpy(myipaddr, s, 20);
10769         debug(F110,"getsockname",myipaddr,0);
10770     }
10771 #endif /* EXCELAN */
10772 #endif /* datageneral */
10773
10774 /* See note in netopen() on Reverse DNS lookups */
10775      if (tcp_rdns == SET_ON) {
10776 #ifdef NT
10777         if (isWin95())
10778           sleep(1);
10779 #endif /* NT */
10780         if (!quiet) {
10781             printf(" Reverse DNS Lookup... ");
10782             fflush(stdout);
10783         }
10784         if (host = gethostbyaddr((char *)&r_addr.sin_addr,4,PF_INET)) {
10785             char * s;
10786             host = ck_copyhostent(host);
10787             debug(F100,"http_open gethostbyname != NULL","",0);
10788             if (!quiet) {
10789                 printf("(OK)\n");
10790                 fflush(stdout);
10791             }
10792             s = host->h_name;
10793             if (!s) {                   /* This can happen... */
10794                 debug(F100,"http_open host->h_name is NULL","",0);
10795                 s = "";
10796             }
10797             /* Something is wrong with inet_ntoa() on HPUX 10.xx */
10798             /* The compiler says "Integral value implicitly converted to */
10799             /* pointer in assignment."  The prototype is right there */
10800             /* in <arpa/inet.h> so what's the problem? */
10801             /* Ditto in HP-UX 5.x, but not 8.x or 9.x... */
10802             if (!*s) {                  /* No name so substitute the address */
10803                 debug(F100,"http_open host->h_name is empty","",0);
10804                 s = inet_ntoa(r_addr.sin_addr); /* Convert address to string */
10805                 if (!s)                 /* Trust No 1 */
10806                   s = "";
10807                 if (*s) {               /* If it worked, use this string */
10808                     ckstrncpy(http_ip,s,20);
10809                 }
10810                 s = http_ip;             /* Otherwise stick with the IP */
10811                 if (!*s)                 /* or failing that */
10812                   s = http_host_port;    /* the name we were called with. */
10813             }
10814             if (*s)                     /* return the rdns name */
10815                 ckmakmsg(rdns_name,rdns_len,s,":",svcname,NULL);
10816
10817             if (!quiet && *s
10818 #ifndef NOICP
10819                 && !doconx
10820 #endif /* NOICP */
10821                 ) {
10822                 printf(" %s connected on port %s\n",s,
10823                        ckuitoa(ntohs(service->s_port)));
10824 #ifdef BETADEBUG
10825                 /* This is simply for testing the DNS entries */
10826                 if (host->h_aliases) {
10827                     char ** a = host->h_aliases;
10828                     while (*a) {
10829                         printf(" alias => %s\n",*a);
10830                         a++;
10831                     }
10832                 }
10833 #endif /* BETADEBUG */
10834             }
10835         } else {
10836             if (!quiet) printf("Failed.\n");
10837         }
10838     } else if (!quiet) printf("(OK)\n");
10839     if (!quiet) fflush(stdout);
10840
10841
10842     if ( tcp_http_proxy ) {
10843         /* Erase the IP address since we cannot reuse it */
10844         http_ip[0] = '\0';
10845     } else {
10846         /* This should already have been done but just in case */
10847         ckstrncpy(http_ip,(char *)inet_ntoa(r_addr.sin_addr),20);
10848     }
10849     makestr(&http_agent,agent);
10850
10851 #ifdef CK_SSL
10852     if (use_ssl && ck_ssleay_is_installed()) {
10853         if (!ssl_http_init(hostname)) {
10854             if (bio_err!=NULL) {
10855                 BIO_printf(bio_err,"ssl_tn_init() failed\n");
10856                 ERR_print_errors(bio_err);
10857             } else {
10858                 fflush(stderr);
10859                 fprintf(stderr,"ssl_tn_init() failed\n");
10860                 ERR_print_errors_fp(stderr);
10861             }
10862             http_close();
10863             return(-1);
10864         } else if ( ck_ssl_http_client(httpfd,hostname) < 0 ) {
10865             http_close();
10866             return(-1);
10867         }
10868     }
10869 #endif /* CK_SSL */
10870 #endif /* TCPSOCKET */
10871
10872     return(0);                          /* Done. */
10873 }
10874
10875 int
10876 #ifdef CK_ANSIC
10877 http_close(VOID)
10878 #else /* CK_ANSIC */
10879 http_close()
10880 #endif /* CK_ANSIC */
10881 {
10882     int x = 0;
10883     debug(F101,"http_close","",httpfd);
10884
10885 #ifdef HTTP_BUFFERING
10886     http_count = 0;
10887     http_bufp = 0;
10888 #endif  /* HTTP_BUFFERING */
10889
10890     if (httpfd == -1)                    /* Was open? */
10891       return(0);                        /* Wasn't. */
10892
10893 #ifndef OS2
10894     if (httpfd > -1)                     /* Was. */
10895 #endif /* OS2 */
10896       {
10897 #ifdef CK_SSL
10898           if (tls_http_active_flag) {
10899               if (ssl_debug_flag)
10900                 BIO_printf(bio_err,"calling SSL_shutdown\n");
10901               SSL_shutdown(tls_http_con);
10902               tls_http_active_flag = 0;
10903           }
10904 #endif /* CK_SSL */
10905 #ifdef TCPIPLIB
10906           x = socket_close(httpfd);      /* Close it. */
10907 #else
10908 #ifndef OS2
10909           x = close(httpfd);
10910 #endif /* OS2 */
10911 #endif /* TCPIPLIB */
10912       }
10913     httpfd = -1;                          /* Mark it as closed. */
10914     /* do not erase http_host_port, http_ip, http_port so they */
10915     /* can be used by http_reopen() */
10916     return(x);
10917 }
10918
10919
10920 /* http_tol()
10921  * Call with s = pointer to string, n = length.
10922  * Returns number of bytes actually written on success, or
10923  * -1 on i/o error, -2 if called improperly.
10924  */
10925
10926 int
10927 http_tol(s,n) CHAR *s; int n; {
10928     int count = 0;
10929     int len = n;
10930     int try = 0;
10931
10932     if (httpfd == -1) {
10933         debug(F100,"http_tol socket is closed","",0);
10934         return -1;
10935     }
10936     debug(F101,"http_tol TCPIPLIB ttnet","",ttnet);
10937 #ifdef COMMENT
10938     ckhexdump("http_tol",s,n);
10939 #endif /* COMMENT */
10940
10941 #ifdef CK_SSL
10942     if (tls_http_active_flag) {
10943         int error, r;
10944         /* Write using SSL */
10945       ssl_retry:
10946           r = SSL_write(tls_http_con, s, len /* >1024?1024:len */);
10947         switch (SSL_get_error(tls_http_con,r)) {
10948           case SSL_ERROR_NONE:
10949             debug(F111,"http_tol","SSL_write",r);
10950             if ( r == len )
10951                 return(n);
10952              s += r;
10953              len -= r;
10954              goto ssl_retry;
10955           case SSL_ERROR_WANT_WRITE:
10956             debug(F100,"http_tol SSL_ERROR_WANT_WRITE","",0);
10957               return(-1);
10958           case SSL_ERROR_WANT_READ:
10959             debug(F100,"http_tol SSL_ERROR_WANT_READ","",0);
10960             return(-1);
10961           case SSL_ERROR_SYSCALL:
10962               if ( r == 0 ) { /* EOF */
10963                   http_close();
10964                   return(-2);
10965               } else {
10966                   int rc = -1;
10967 #ifdef NT
10968                   int gle = GetLastError();
10969                   debug(F111,"http_tol SSL_ERROR_SYSCALL",
10970                          "GetLastError()",gle);
10971                   rc = os2socketerror(gle);
10972                   if (rc == -1)
10973                       rc = -2;
10974                   else if ( rc == -2 )
10975                       return -1;
10976 #endif /* NT */
10977                   return(rc);
10978               }
10979           case SSL_ERROR_WANT_X509_LOOKUP:
10980             debug(F100,"http_tol SSL_ERROR_WANT_X509_LOOKUP","",0);
10981             http_close();
10982             return(-2);
10983           case SSL_ERROR_SSL:
10984             debug(F100,"http_tol SSL_ERROR_SSL","",0);
10985             http_close();
10986             return(-2);
10987           case SSL_ERROR_ZERO_RETURN:
10988             debug(F100,"http_tol SSL_ERROR_ZERO_RETURN","",0);
10989             http_close();
10990             return(-2);
10991           default:
10992             debug(F100,"http_tol SSL_ERROR_?????","",0);
10993             http_close();
10994             return(-2);
10995         }
10996     }
10997 #endif /* CK_SSL */
10998
10999   http_tol_retry:
11000     try++;                              /* Increase the try counter */
11001
11002     {
11003 #ifdef BSDSELECT
11004         fd_set wfds;
11005         struct timeval tv;
11006
11007         debug(F101,"http_tol BSDSELECT","",0);
11008         tv.tv_usec = 0L;
11009         tv.tv_sec=30;
11010 #ifdef NT
11011         WSASafeToCancel = 1;
11012 #endif /* NT */
11013 #ifdef STREAMING
11014       do_select:
11015 #endif /* STREAMING */
11016         FD_ZERO(&wfds);
11017         FD_SET(httpfd, &wfds);
11018         if (select(FD_SETSIZE, NULL,
11019 #ifdef __DECC
11020 #ifndef __DECC_VER
11021                     (int *)
11022 #endif /* __DECC_VER */
11023 #endif /* __DECC */
11024                    &wfds, NULL, &tv) < 0) {
11025             int s_errno = socket_errno;
11026             debug(F101,"http_tol select failed","",s_errno);
11027 #ifdef BETADEBUG
11028             printf("http_tol select failed: %d\n", s_errno);
11029 #endif /* BETADEBUG */
11030 #ifdef NT
11031             WSASafeToCancel = 0;
11032             if (!win95selectbug)
11033 #endif /* NT */
11034               return(-1);
11035         }
11036         if (!FD_ISSET(httpfd, &wfds)) {
11037 #ifdef STREAMING
11038             if (streaming)
11039               goto do_select;
11040 #endif /* STREAMING */
11041             debug(F111,"http_tol","!FD_ISSET",ttyfd);
11042 #ifdef NT
11043             WSASafeToCancel = 0;
11044             if (!win95selectbug)
11045 #endif /* NT */
11046               return(-1);
11047         }
11048 #ifdef NT
11049         WSASafeToCancel = 0;
11050 #endif /* NT */
11051 #else /* BSDSELECT */
11052 #ifdef IBMSELECT
11053         {
11054             int tries = 0;
11055             debug(F101,"http_tol IBMSELECT","",0);
11056             while (select(&httpfd, 0, 1, 0, 1000) != 1) {
11057                 int count;
11058                 if (tries++ >= 60) {
11059                     /* if after 60 seconds we can't get permission to write */
11060                     debug(F101,"http_tol select failed","",socket_errno);
11061                     return(-1);
11062                 }
11063 #ifdef COMMENT
11064                 if ((count = http_tchk()) < 0) {
11065                     debug(F111,"http_tol","http_tchk()",count);
11066                     return(count);
11067                 }
11068 #endif /* COMMENT */
11069             }
11070         }
11071 #endif /* IBMSELECT */
11072 #endif /* BSDSELECT */
11073 #ifdef TCPIPLIB
11074         if ((count = socket_write(httpfd,s,n)) < 0) {
11075             int s_errno = socket_errno; /* maybe a function */
11076             debug(F101,"http_tol socket_write error","",s_errno);
11077 #ifdef OS2
11078             if (os2socketerror(s_errno) < 0)
11079               return(-2);
11080 #endif /* OS2 */
11081             return(-1);                 /* Call it an i/o error */
11082         }
11083 #else /* TCPIPLIB */
11084         if ((count = write(httpfd,s,n)) < 0) {
11085             debug(F101,"http_tol socket_write error","",errno);
11086             return(-1);                 /* Call it an i/o error */
11087         }
11088 #endif /* TCPIPLIB */
11089         if (count < n) {
11090             debug(F111,"http_tol socket_write",s,count);
11091             if (try > 25) {
11092                 /* don't try more than 25 times */
11093                 debug(F100,"http_tol tried more than 25 times","",0);
11094                 return(-1);
11095             }
11096             if (count > 0) {
11097                 s += count;
11098                 n -= count;
11099             }
11100             debug(F111,"http_tol retry",s,n);
11101             goto http_tol_retry;
11102         } else {
11103             debug(F111,"http_tol socket_write",s,count);
11104             return(len); /* success - return total length */
11105         }
11106     }
11107 }
11108
11109 int
11110 http_inc(timo) int timo; {
11111     int x=-1; unsigned char c;             /* The locals. */
11112
11113     if (httpfd == -1) {
11114 #ifdef HTTP_BUFFERING
11115         http_count = 0;
11116         http_bufp = 0;
11117 #endif  /* HTTP_BUFFERING */
11118         debug(F100,"http_inc socket is closed","",0);
11119         return(-2);
11120     }
11121
11122 #ifdef CK_SSL
11123     /*
11124      * In the case of OpenSSL, it is possible that there is still
11125      * data waiting in the SSL session buffers that has not yet
11126      * been read by Kermit.  If this is the case we must process
11127      * it without calling select() because select() will not return
11128      * with an indication that there is data to be read from the
11129      * socket.  If there is no data pending in the SSL session
11130      * buffers then fall through to the select() code and wait for
11131      * some data to arrive.
11132      */
11133     if (tls_http_active_flag) {
11134         int error;
11135
11136         x = SSL_pending(tls_http_con);
11137         if (x < 0) {
11138             debug(F111,"http_inc","SSL_pending error",x);
11139             http_close();
11140             return(-1);
11141         } else if ( x > 0 ) {
11142           ssl_read:
11143             x = SSL_read(tls_http_con, &c, 1);
11144             error = SSL_get_error(tls_http_con,x);
11145             switch (error) {
11146             case SSL_ERROR_NONE:
11147                 debug(F111,"http_inc SSL_ERROR_NONE","x",x);
11148                 if (x > 0) {
11149 #ifdef OS2
11150                     ReleaseTCPIPMutex();
11151 #endif /* OS2 */
11152                     return(c);          /* Return character. */
11153                 } else if (x < 0) {
11154 #ifdef OS2
11155                     ReleaseTCPIPMutex();
11156 #endif /* OS2 */
11157                     return(-1);
11158                 } else {
11159                     http_close();
11160 #ifdef OS2
11161                     ReleaseTCPIPMutex();
11162 #endif /* OS2 */
11163                     return(-2);
11164                 }
11165             case SSL_ERROR_WANT_WRITE:
11166                 debug(F100,"http_inc SSL_ERROR_WANT_WRITE","",0);
11167 #ifdef OS2
11168                 ReleaseTCPIPMutex();
11169 #endif /* OS2 */
11170                 return(-1);
11171             case SSL_ERROR_WANT_READ:
11172                 debug(F100,"http_inc SSL_ERROR_WANT_READ","",0);
11173 #ifdef OS2
11174                 ReleaseTCPIPMutex();
11175 #endif /* OS2 */
11176                 return(-1);
11177             case SSL_ERROR_SYSCALL:
11178                 if ( x == 0 ) { /* EOF */
11179                     http_close();
11180 #ifdef OS2
11181                     ReleaseTCPIPMutex();
11182 #endif /* OS2 */
11183                     return(-2);
11184                 } else {
11185                     int rc = -1;
11186 #ifdef NT
11187                     int gle = GetLastError();
11188                     debug(F111,"http_inc SSL_ERROR_SYSCALL",
11189                            "GetLastError()",gle);
11190                     rc = os2socketerror(gle);
11191                     if (rc == -1)
11192                         rc = -2;
11193                     else if ( rc == -2 )
11194                         rc = -1;
11195 #endif /* NT */
11196 #ifdef OS2
11197                     ReleaseTCPIPMutex();
11198 #endif /* OS2 */
11199                     return(rc);
11200                 }
11201             case SSL_ERROR_WANT_X509_LOOKUP:
11202                 debug(F100,"http_inc SSL_ERROR_WANT_X509_LOOKUP","",0);
11203                 http_close();
11204 #ifdef OS2
11205                 ReleaseTCPIPMutex();
11206 #endif /* OS2 */
11207                 return(-2);
11208             case SSL_ERROR_SSL:
11209                 debug(F100,"http_inc SSL_ERROR_SSL","",0);
11210 #ifdef COMMENT
11211                 http_close();
11212 #endif /* COMMENT */
11213 #ifdef OS2
11214                 ReleaseTCPIPMutex();
11215 #endif /* OS2 */
11216                 return(-2);
11217             case SSL_ERROR_ZERO_RETURN:
11218                 debug(F100,"http_inc SSL_ERROR_ZERO_RETURN","",0);
11219                 http_close();
11220 #ifdef OS2
11221                 ReleaseTCPIPMutex();
11222 #endif /* OS2 */
11223                 return(-2);
11224             default:
11225                 debug(F100,"http_inc SSL_ERROR_?????","",0);
11226                 http_close();
11227 #ifdef OS2
11228                 ReleaseTCPIPMutex();
11229 #endif /* OS2 */
11230                 return(-2);
11231             }
11232         }
11233     }
11234 #endif /* CK_SSL */
11235
11236 #ifdef HTTP_BUFFERING
11237     /* Skip all the select() stuff if we have bytes buffered locally */
11238     if (http_count > 0)
11239       goto getfrombuffer;
11240 #endif  /* HTTP_BUFFERING */
11241
11242     {
11243 #ifdef BSDSELECT
11244         fd_set rfds;
11245         struct timeval tv;
11246         int timeout = timo < 0 ? -timo : 1000 * timo;
11247         debug(F101,"http_inc BSDSELECT","",timo);
11248
11249         for ( ; timeout >= 0; timeout -= (timo ? 100 : 0)) {
11250             int rc;
11251             debug(F111,"http_inc","timeout",timeout);
11252             /* Don't move select() initialization out of the loop. */
11253             FD_ZERO(&rfds);
11254             FD_SET(httpfd, &rfds);
11255             tv.tv_sec  = tv.tv_usec = 0L;
11256             if (timo)
11257                 tv.tv_usec = (long) 100000L;
11258             else
11259                 tv.tv_sec = 30;
11260 #ifdef NT
11261             WSASafeToCancel = 1;
11262 #endif /* NT */
11263             rc = select(FD_SETSIZE,
11264 #ifndef __DECC
11265                          (fd_set *)
11266 #endif /* __DECC */
11267                          &rfds, NULL, NULL, &tv);
11268             if (rc < 0) {
11269                 int s_errno = socket_errno;
11270                 debug(F111,"http_inc","select",rc);
11271                 debug(F111,"http_inc","socket_errno",s_errno);
11272 #ifdef HTTP_BUFFERING
11273                 http_count = 0;
11274                 http_bufp = 0;
11275 #endif  /* HTTP_BUFFERING */
11276                 if (s_errno)
11277                     return(-1);
11278             }
11279             debug(F111,"http_inc","select",rc);
11280 #ifdef NT
11281             WSASafeToCancel = 0;
11282 #endif /* NT */
11283             if (FD_ISSET(httpfd, &rfds)) {
11284                 x = 0;
11285                 break;
11286             } else {
11287                 /* If waiting forever we have no way of knowing if the */
11288                 /* socket closed so try writing a 0-length TCP packet  */
11289                 /* which should force an error if the socket is closed */
11290                 if (!timo) {
11291 #ifdef TCPIPLIB
11292                     if ((rc = socket_write(httpfd,"",0)) < 0) {
11293 #ifdef HTTP_BUFFERING
11294                         http_count = 0;
11295                         http_bufp = 0;
11296 #endif  /* HTTP_BUFFERING */
11297                         int s_errno = socket_errno;
11298                         debug(F101,"http_inc socket_write error","",s_errno);
11299 #ifdef OS2
11300                         if (os2socketerror(s_errno) < 0)
11301                             return(-2);
11302 #endif /* OS2 */
11303                         return(-1); /* Call it an i/o error */
11304                     }
11305 #else /* TCPIPLIB */
11306                     if ((rc = write(httpfd,"",0)) < 0) {
11307 #ifdef HTTP_BUFFERING
11308                         http_count = 0;
11309                         http_bufp = 0;
11310 #endif  /* HTTP_BUFFERING */
11311                         debug(F101,"http_inc socket_write error","",errno);
11312                         return(-1); /* Call it an i/o error */
11313                     }
11314 #endif /* TCPIPLIB */
11315                 }
11316                 continue;
11317             }
11318         }
11319 #ifdef NT
11320         WSASafeToCancel = 0;
11321 #endif /* NT */
11322 #else /* !BSDSELECT */
11323 #ifdef IBMSELECT
11324  /*
11325   Was used by OS/2, currently not used, but might come in handy some day...
11326   ... and it came in handy!  For our TCP/IP layer, it avoids all the fd_set
11327   and timeval stuff since this is the only place where it is used.
11328  */
11329         int socket = httpfd;
11330         int timeout = timo < 0 ? -timo : 1000 * timo;
11331
11332         debug(F101,"http_inc IBMSELECT","",timo);
11333         for ( ; timeout >= 0; timeout -= (timo ? 100 : 0)) {
11334             if (select(&socket, 1, 0, 0, 100L) == 1) {
11335                 x = 0;
11336                 break;
11337             }
11338         }
11339 #else /* !IBMSELECT */
11340         SELECT is required for this code
11341 #endif /* IBMSELECT */
11342 #endif /* BSDSELECT */
11343     }
11344
11345     if (timo && x < 0) {        /* select() timed out */
11346 #ifdef HTTP_BUFFERING
11347         http_count = 0;
11348         http_bufp = 0;
11349 #endif  /* HTTP_BUFFERING */
11350         debug(F100,"http_inc select() timed out","",0);
11351         return(-1); /* Call it an i/o error */
11352     }
11353
11354 #ifdef CK_SSL
11355         if ( tls_http_active_flag ) {
11356             int error;
11357           ssl_read2:
11358             x = SSL_read(tls_http_con, &c, 1);
11359             error = SSL_get_error(tls_http_con,x);
11360             switch (error) {
11361             case SSL_ERROR_NONE:
11362                 debug(F111,"http_inc SSL_ERROR_NONE","x",x);
11363                 if (x > 0) {
11364 #ifdef OS2
11365                     ReleaseTCPIPMutex();
11366 #endif /* OS2 */
11367                     return(c);          /* Return character. */
11368                 } else if (x < 0) {
11369 #ifdef OS2
11370                     ReleaseTCPIPMutex();
11371 #endif /* OS2 */
11372                     return(-1);
11373                 } else {
11374                     http_close();
11375 #ifdef OS2
11376                     ReleaseTCPIPMutex();
11377 #endif /* OS2 */
11378                     return(-2);
11379                 }
11380             case SSL_ERROR_WANT_WRITE:
11381                 debug(F100,"http_inc SSL_ERROR_WANT_WRITE","",0);
11382 #ifdef OS2
11383                 ReleaseTCPIPMutex();
11384 #endif /* OS2 */
11385                 return(-1);
11386             case SSL_ERROR_WANT_READ:
11387                 debug(F100,"http_inc SSL_ERROR_WANT_READ","",0);
11388 #ifdef OS2
11389                 ReleaseTCPIPMutex();
11390 #endif /* OS2 */
11391                 return(-1);
11392             case SSL_ERROR_SYSCALL:
11393                 if ( x == 0 ) { /* EOF */
11394                     http_close();
11395 #ifdef OS2
11396                     ReleaseTCPIPMutex();
11397 #endif /* OS2 */
11398                     return(-2);
11399                 } else {
11400                     int rc = -1;
11401 #ifdef NT
11402                     int gle = GetLastError();
11403                     debug(F111,"http_inc SSL_ERROR_SYSCALL",
11404                            "GetLastError()",gle);
11405                     rc = os2socketerror(gle);
11406                     if (rc == -1)
11407                         rc = -2;
11408                     else if ( rc == -2 )
11409                         rc = -1;
11410 #endif /* NT */
11411 #ifdef OS2
11412                     ReleaseTCPIPMutex();
11413 #endif /* OS2 */
11414                     return(rc);
11415                 }
11416             case SSL_ERROR_WANT_X509_LOOKUP:
11417                 debug(F100,"http_inc SSL_ERROR_WANT_X509_LOOKUP","",0);
11418                 http_close();
11419 #ifdef OS2
11420                 ReleaseTCPIPMutex();
11421 #endif /* OS2 */
11422                 return(-2);
11423             case SSL_ERROR_SSL:
11424                 debug(F100,"http_inc SSL_ERROR_SSL","",0);
11425 #ifdef COMMENT
11426                 http_close();
11427 #endif /* COMMENT */
11428 #ifdef OS2
11429                 ReleaseTCPIPMutex();
11430 #endif /* OS2 */
11431                 return(-2);
11432             case SSL_ERROR_ZERO_RETURN:
11433                 debug(F100,"http_inc SSL_ERROR_ZERO_RETURN","",0);
11434                 http_close();
11435 #ifdef OS2
11436                 ReleaseTCPIPMutex();
11437 #endif /* OS2 */
11438                 return(-2);
11439             default:
11440                 debug(F100,"http_inc SSL_ERROR_?????","",0);
11441                 http_close();
11442 #ifdef OS2
11443                 ReleaseTCPIPMutex();
11444 #endif /* OS2 */
11445                 return(-2);
11446             }
11447         }
11448 #endif /* CK_SSL */
11449
11450 #ifdef HTTP_BUFFERING
11451 /*
11452   Buffering code added by fdc 15 Dec 2005 for non-SSL case only because HTTP
11453   GETs were orders of magnitude too slow due to the single-byte read()s.  The
11454   file-descriptor swapping is pretty gross, but the more elegant solution
11455   (calling a nettchk() like routine with the fd as a parameter) doesn't work,
11456   because nettchk() relies on too many other routines that, like itself, are
11457   hardwired for ttyfd.
11458 */
11459   getfrombuffer:
11460         if (--http_count >= 0) {
11461             c = http_inbuf[http_bufp++];
11462             x = 1;
11463         } else {
11464             int savefd;
11465             savefd = ttyfd;
11466             ttyfd = httpfd;
11467             x = nettchk();
11468             ttyfd = savefd;             
11469             debug(F101,"http_inc nettchk","",x);
11470             if (x > HTTP_INBUFLEN)
11471               x = HTTP_INBUFLEN;
11472 #ifdef TCPIPLIB
11473             x = socket_read(httpfd,http_inbuf,x);
11474 #else  /* Not TCPIPLIB */
11475             x = read(httpfd,http_inbuf,x);
11476 #endif  /* TCPIPLIB */
11477             http_count = 0;
11478             http_bufp = 0;
11479             if (x > 0) {
11480                 c = http_inbuf[http_bufp++];
11481                 http_count = x - 1;
11482             }
11483         }
11484 #else  /* Not HTTP_BUFFERING */
11485 #ifdef TCPIPLIB
11486         x = socket_read(httpfd,&c,1);
11487 #else  /* Not TCPIPLIB */
11488         x = read(httpfd,&c,1);
11489 #endif  /* TCPIPLIB */
11490 #endif  /* HTTP_BUFFERING */
11491
11492         if (x <= 0) {
11493             int s_errno = socket_errno;
11494             debug(F101,"ttbufr socket_read","",x);
11495             debug(F101,"ttbufr socket_errno","",s_errno);
11496 #ifdef OS2
11497             if (x == 0 || os2socketerror(s_errno) < 0) {
11498                 http_close();
11499                 ReleaseTCPIPMutex();
11500                 return(-2);
11501             }
11502             ReleaseTCPIPMutex();
11503             return(-1);
11504 #else /* OS2 */
11505             http_close();                      /* *** *** */
11506             return(-2);
11507 #endif /* OS2 */
11508         }
11509         return(c);
11510 }
11511
11512 void
11513 #ifdef CK_ANSIC
11514 http_set_code_reply(char * msg)
11515 #else
11516 http_set_code_reply(msg)
11517     char * msg;
11518 #endif /* CK_ANSIC */
11519 {
11520     char * p = msg;
11521     char buf[16];
11522     int i=0;
11523
11524     while ( *p != SP && *p != NUL ) {
11525         buf[i] = *p;
11526         p++;
11527         i++;
11528     }
11529
11530     http_code = atoi(buf);
11531
11532     while ( *p == SP )
11533         p++;
11534
11535     ckstrncpy(http_reply_str,p,HTTPBUFLEN);
11536 }
11537
11538 int
11539 #ifdef CK_ANSIC
11540 http_get(char * agent, char ** hdrlist, char * user,
11541          char * pwd, char array, char * local, char * remote,
11542          int stdio)
11543 #else
11544 http_get(agent, hdrlist, user, pwd, array, local, remote, stdio)
11545     char * agent; char ** hdrlist; char * user;
11546     char * pwd; char array; char * local; char * remote;
11547     int stdio;
11548 #endif /* CK_ANSIC */
11549 {
11550     char * request = NULL;
11551     int    i, j, len = 0, hdcnt = 0, rc = 0;
11552     int    ch;
11553     int    http_fnd = 0;
11554     char   buf[HTTPBUFLEN], *p;
11555     int    nullline;
11556 #ifdef OS2
11557     struct utimbuf u_t;
11558 #else /* OS2 */
11559 #ifdef SYSUTIMEH
11560     struct utimbuf u_t;
11561 #else
11562     struct utimbuf {
11563         time_t atime;
11564         time_t mtime;
11565     } u_t;
11566 #endif /* SYSUTIMH */
11567 #endif /* OS2 */
11568     time_t mod_t = 0;
11569     time_t srv_t = 0;
11570     time_t local_t = 0;
11571     char passwd[64];
11572     char b64in[128];
11573     char b64out[256];
11574     char * headers[HTTPHEADCNT];
11575     int closecon = 0;
11576     int chunked = 0;
11577     int zfile = 0;
11578     int first = 1;
11579
11580 #ifdef DEBUG
11581     if (deblog) {
11582         debug(F101,"http_get httpfd","",httpfd);
11583         debug(F110,"http_agent",agent,0);
11584         debug(F110,"http_user",user,0);
11585         debug(F110,"http_local",local,0);
11586         debug(F110,"http_remote",remote,0);
11587     }
11588 #endif /* DEBUG */
11589     if (!remote) remote = "";
11590
11591     if (httpfd == -1)
11592       return(-1);
11593
11594     if (array) {
11595         for (i = 0; i < HTTPHEADCNT; i++)
11596           headers[i] = NULL;
11597     }
11598     len = 8;                            /* GET */
11599     len += strlen(HTTP_VERSION);
11600     len += strlen(remote);
11601     len += 16;
11602
11603     if (hdrlist) {
11604         for (i = 0; hdrlist[i]; i++)
11605             len += strlen(hdrlist[i]) + 2;
11606     }
11607     len += (int) strlen(http_host_port) + 8;
11608
11609     if (agent)
11610       len += 13 + strlen(agent);
11611     if (user) {
11612         if (!pwd) {
11613             readpass("Password: ",passwd,64);
11614             pwd = passwd;
11615         }
11616         ckmakmsg(b64in,sizeof(b64in),user,":",pwd,NULL);
11617         j = b8tob64(b64in,strlen(b64in),b64out,256);
11618         memset(pwd,0,strlen(pwd));      /* NOT PORTABLE */
11619         if (j < 0)
11620           return(-1);
11621         b64out[j] = '\0';
11622         len += j + 24;
11623     }
11624 #ifdef HTTP_CLOSE
11625     len += 19;                          /* Connection: close */
11626 #endif
11627     len += 3;                           /* blank line + null */
11628
11629     request = malloc(len);
11630     if (!request)
11631       return(-1);
11632
11633     sprintf(request,"GET %s %s\r\n",remote,HTTP_VERSION);       /* safe */
11634     ckstrncat(request,"Host: ", len);
11635     ckstrncat(request,http_host_port, len);
11636     ckstrncat(request,"\r\n",len);
11637     if (agent) {
11638         ckstrncat(request,"User-agent: ",len);
11639         ckstrncat(request,agent,len);
11640         ckstrncat(request,"\r\n",len);
11641     }
11642     if (user) {
11643         ckstrncat(request,"Authorization: Basic ",len);
11644         ckstrncat(request,b64out,len);
11645         ckstrncat(request,"\r\n",len);
11646     }
11647     if ( hdrlist ) {
11648         for (i = 0; hdrlist[i]; i++) {
11649             ckstrncat(request,hdrlist[i],len);
11650             ckstrncat(request,"\r\n",len);
11651         }
11652     }
11653 #ifdef HTTP_CLOSE
11654     ckstrncat(request,"Connection: close\r\n",len);
11655 #endif
11656     ckstrncat(request,"\r\n",len);
11657
11658   getreq:
11659     if (http_tol((CHAR *)request,strlen(request)) < 0)
11660     {
11661         http_close();
11662         if ( first ) {
11663             first--;
11664             http_reopen();
11665             goto getreq;
11666         }
11667         rc = -1;
11668         goto getexit;
11669     }
11670
11671     /* Process the headers */
11672     local_t = time(NULL);
11673     nullline = 0;
11674     i = 0;
11675     len = -1;
11676     while (!nullline && (ch = http_inc(0)) >= 0 && i < HTTPBUFLEN) {
11677         buf[i] = ch;
11678         if ( buf[i] == 10 ) { /* found end of line */
11679             if (i > 0 && buf[i-1] == 13)
11680               i--;
11681             if (i < 1)
11682               nullline = 1;
11683             buf[i] = '\0';
11684             if (array && !nullline && hdcnt < HTTPHEADCNT)
11685               makestr(&headers[hdcnt++],buf);
11686             if (!ckstrcmp(buf,"HTTP",4,0)) {
11687                 http_fnd = 1;
11688                 j = ckindex(" ",buf,0,0,0);
11689                 p = &buf[j];
11690                 while ( isspace(*p) )
11691                   p++;
11692                 switch ( p[0] ) {
11693                   case '1':             /* Informational message */
11694                     break;
11695                   case '2':             /* Success */
11696                     break;
11697                   case '3':             /* Redirection */
11698                   case '4':             /* Client failure */
11699                   case '5':             /* Server failure */
11700                   default:              /* Unknown */
11701                     if (!quiet)
11702                       printf("Failure: Server reports %s\n",p);
11703                     rc = -1;
11704                     local = NULL;
11705                 }
11706                 http_set_code_reply(p);
11707 #ifdef CMDATE2TM
11708             } else if (!ckstrcmp(buf,"Last-Modified",13,0)) {
11709                 mod_t = http_date(&buf[15]);
11710             } else if (!ckstrcmp(buf,"Date",4,0)) {
11711                 srv_t = http_date(&buf[4]);
11712 #endif /* CMDATE2TM */
11713             } else if (!ckstrcmp(buf,"Connection:",11,0)) {
11714                 if ( ckindex("close",buf,11,0,0) != 0 )
11715                     closecon = 1;
11716             } else if (!ckstrcmp(buf,"Content-Length:",15,0)) {
11717                 len = atoi(&buf[16]);
11718             } else if (!ckstrcmp(buf,"Transfer-Encoding:",18,0)) {
11719                 if ( ckindex("chunked",buf,18,0,0) != 0 )
11720                     chunked = 1;
11721                 debug(F101,"http_get chunked","",chunked);
11722             }
11723             i = 0;
11724         } else {
11725             i++;
11726         }
11727     }
11728     if (ch < 0 && first) {
11729         first--;
11730         http_close();
11731         http_reopen();
11732         goto getreq;
11733     }
11734     if (http_fnd == 0) {
11735         rc = -1;
11736         closecon = 1;
11737         goto getexit;
11738     }
11739
11740     /* Now we have the contents of the file */
11741     if ( local && local[0] ) {
11742         if (zopeno(ZOFILE,local,NULL,NULL))
11743             zfile = 1;
11744         else
11745             rc = -1;
11746     }
11747
11748     if ( chunked ) {
11749         while ((len = http_get_chunk_len()) > 0) {
11750             while (len && (ch = http_inc(0)) >= 0) {
11751                 len--;
11752                 if ( zfile )
11753                     zchout(ZOFILE,(CHAR)ch);
11754                 if ( stdio )
11755                     conoc((CHAR)ch);
11756             }
11757             if ((ch = http_inc(0)) != CR)
11758                 break;
11759             if ((ch = http_inc(0)) != LF)
11760                 break;
11761         }
11762     } else {
11763         while (len && (ch = http_inc(0)) >= 0) {
11764             len--;
11765             if ( zfile )
11766                 zchout(ZOFILE,(CHAR)ch);
11767             if ( stdio )
11768                 conoc((CHAR)ch);
11769         }
11770     }
11771
11772     if ( zfile )
11773         zclose(ZOFILE);
11774
11775     if ( chunked ) {            /* Parse Trailing Headers */
11776         nullline = 0;
11777         while (!nullline && (ch = http_inc(0)) >= 0 && i < HTTPBUFLEN) {
11778             buf[i] = ch;
11779             if ( buf[i] == 10 ) { /* found end of line */
11780                 if (i > 0 && buf[i-1] == 13)
11781                   i--;
11782                 if (i < 1)
11783                   nullline = 1;
11784                 buf[i] = '\0';
11785                 if (array && !nullline && hdcnt < HTTPHEADCNT)
11786                     makestr(&headers[hdcnt++],buf);
11787 #ifdef CMDATE2TM
11788                 if (!ckstrcmp(buf,"Last-Modified",13,0)) {
11789                     mod_t = http_date(&buf[15]);
11790                 } else if (!ckstrcmp(buf,"Date",4,0)) {
11791                     srv_t = http_date(&buf[4]);
11792                 }
11793 #endif /* CMDATE2TM */
11794                 else if (!ckstrcmp(buf,"Connection:",11,0)) {
11795                     if ( ckindex("close",buf,11,0,0) != 0 )
11796                         closecon = 1;
11797                 }
11798                 i = 0;
11799             } else {
11800                 i++;
11801             }
11802         }
11803     }
11804
11805     if ( zfile ) {              /* Set timestamp */
11806 #ifndef NOSETTIME
11807 #ifdef OS2
11808         u_t.actime = srv_t ? srv_t : local_t;
11809         u_t.modtime = mod_t ? mod_t : local_t;
11810 #else /* OS2 */
11811 #ifdef SYSUTIMEH
11812         u_t.actime = srv_t ? srv_t : local_t;
11813         u_t.modtime = mod_t ? mod_t : local_t;
11814 #else
11815 #ifdef BSD44
11816         u_t[0].tv_sec = srv_t ? srv_t : local_t;
11817         u_t[1].tv_sec = mod_t ? mod_t : local_t;
11818 #else
11819         u_t.mtime = srv_t ? srv_t : local_t;
11820         u_t.atime = mod_t ? mod_t : local_t;
11821 #endif /* BSD44 */
11822 #endif /* SYSUTIMEH */
11823 #endif /* OS2 */
11824             utime(local,&u_t);
11825 #endif /* NOSETTIME */
11826     }
11827
11828   getexit:
11829     if (array)
11830       http_mkarray(headers,hdcnt,array);
11831
11832     if ( closecon )
11833         http_close();
11834     free(request);
11835     for (i = 0; i < hdcnt; i++) {
11836         if (headers[i])
11837           free(headers[i]);
11838     }
11839     return(rc);
11840 }
11841
11842 int
11843 #ifdef CK_ANSIC
11844 http_head(char * agent, char ** hdrlist, char * user,
11845           char * pwd, char array, char * local, char * remote,
11846           int stdio)
11847 #else
11848 http_head(agent, hdrlist, user, pwd, array, local, remote, stdio)
11849     char * agent; char ** hdrlist; char * user;
11850     char * pwd; char array; char * local; char * remote;
11851     int stdio;
11852 #endif /* CK_ANSIC */
11853 {
11854     char * request = NULL;
11855     int    i, j, len = 0, hdcnt = 0, rc = 0;
11856     int    ch;
11857     int    http_fnd = 0;
11858     char   buf[HTTPBUFLEN], *p;
11859     int    nullline;
11860     time_t mod_t;
11861     time_t srv_t;
11862     time_t local_t;
11863     char passwd[64];
11864     char b64in[128];
11865     char b64out[256];
11866     char * headers[HTTPHEADCNT];
11867     int  closecon = 0;
11868     int  first = 1;
11869
11870     if (httpfd == -1)
11871       return(-1);
11872
11873     if (array) {
11874         for (i = 0; i < HTTPHEADCNT; i++)
11875           headers[i] = NULL;
11876     }
11877     len = 9;                            /* HEAD */
11878     len += strlen(HTTP_VERSION);
11879     len += strlen(remote);
11880     len += 16;
11881
11882     if ( hdrlist ) {
11883         for (i = 0; hdrlist[i]; i++)
11884             len += strlen(hdrlist[i]) + 2;
11885     }
11886     len += strlen(http_host_port) + 8;
11887
11888     if (agent)
11889       len += 13 + strlen(agent);
11890     if (user) {
11891         if (!pwd) {
11892             readpass("Password: ",passwd,64);
11893             pwd = passwd;
11894         }
11895         ckmakmsg(b64in,sizeof(b64in),user,":",pwd,NULL);
11896         j = b8tob64(b64in,strlen(b64in),b64out,256);
11897         memset(pwd,0,strlen(pwd));      /* NOT PORTABLE */
11898         if (j < 0)
11899           return(-1);
11900         b64out[j] = '\0';
11901         len += j + 24;
11902     }
11903 #ifdef HTTP_CLOSE
11904     len += 19;                          /* Connection: close */
11905 #endif
11906     len += 3;                           /* blank line + null */
11907
11908     request = (char *)malloc(len);
11909     if (!request)
11910       return(-1);
11911
11912     sprintf(request,"HEAD %s %s\r\n",remote,HTTP_VERSION);
11913     ckstrncat(request,"Host: ", len);
11914     ckstrncat(request,http_host_port, len);
11915     ckstrncat(request,"\r\n",len);
11916     if (agent) {
11917         ckstrncat(request,"User-agent: ",len);
11918         ckstrncat(request,agent,len);
11919         ckstrncat(request,"\r\n",len);
11920     }
11921     if (user) {
11922         ckstrncat(request,"Authorization: Basic ",len);
11923         ckstrncat(request,b64out,len);
11924         ckstrncat(request,"\r\n",len);
11925     }
11926     if ( hdrlist ) {
11927         for (i = 0; hdrlist[i]; i++) {
11928             ckstrncat(request,hdrlist[i],len);
11929             ckstrncat(request,"\r\n",len);
11930         }
11931     }
11932 #ifdef HTTP_CLOSE
11933     ckstrncat(request,"Connection: close\r\n",len);
11934 #endif
11935     ckstrncat(request,"\r\n",len);
11936
11937     if ( local && local[0] ) {
11938         if (!zopeno(ZOFILE,local,NULL,NULL)) {
11939             free(request);
11940             return(-1);
11941         }
11942     }
11943
11944   headreq:
11945     if (http_tol((CHAR *)request,strlen(request)) < 0)
11946     {
11947         http_close();
11948         if ( first ) {
11949             first--;
11950             http_reopen();
11951             goto headreq;
11952         }
11953         rc = -1;
11954         goto headexit;
11955     }
11956
11957     /* Process the headers */
11958
11959     local_t = time(NULL);
11960     nullline = 0;
11961     i = 0;
11962     while (!nullline && (ch = http_inc(0)) >= 0 && i < HTTPBUFLEN) {
11963         buf[i] = ch;
11964         if (buf[i] == 10) {             /* found end of line */
11965             if (i > 0 && buf[i-1] == 13)
11966               i--;
11967             if (i < 1)
11968               nullline = 1;
11969             buf[i] = '\0';
11970             if (array && !nullline && hdcnt < HTTPHEADCNT)
11971               makestr(&headers[hdcnt++],buf);
11972             if (!ckstrcmp(buf,"HTTP",4,0)) {
11973                 http_fnd = 1;
11974                 j = ckindex(" ",buf,0,0,0);
11975                 p = &buf[j];
11976                 while (isspace(*p))
11977                   p++;
11978                 switch (p[0]) {
11979                   case '1':             /* Informational message */
11980                     break;
11981                   case '2':             /* Success */
11982                     break;
11983                   case '3':             /* Redirection */
11984                   case '4':             /* Client failure */
11985                   case '5':             /* Server failure */
11986                   default:              /* Unknown */
11987                     if (!quiet)
11988                       printf("Failure: Server reports %s\n",p);
11989                     rc = -1;
11990                 }
11991                 http_set_code_reply(p);
11992             } else {
11993                 if (!ckstrcmp(buf,"Connection:",11,0)) {
11994                     if ( ckindex("close",buf,11,0,0) != 0 )
11995                         closecon = 1;
11996                 }
11997                 if ( local && local[0] ) {
11998                     zsout(ZOFILE,buf);
11999                     zsout(ZOFILE,"\r\n");
12000                 }
12001                 if (stdio)
12002                     printf("%s\r\n",buf);
12003             }
12004             i = 0;
12005         } else {
12006             i++;
12007         }
12008     }
12009     if (ch < 0 && first) {
12010         first--;
12011         http_close();
12012         http_reopen();
12013         goto headreq;
12014     }
12015     if ( http_fnd == 0 )
12016         rc = -1;
12017
12018     if (array)
12019       http_mkarray(headers,hdcnt,array);
12020
12021   headexit:
12022     if ( local && local[0] )
12023         zclose(ZOFILE);
12024     if (closecon)
12025         http_close();
12026     free(request);
12027     for (i = 0; i < hdcnt; i++) {
12028         if (headers[i])
12029           free(headers[i]);
12030     }
12031     return(rc);
12032 }
12033
12034 int
12035 #ifdef CK_ANSIC
12036 http_index(char * agent, char ** hdrlist, char * user, char * pwd,
12037              char array, char * local, char * remote, int stdio)
12038 #else
12039 http_index(agent, hdrlist, user, pwd, array, local, remote, stdio)
12040     char * agent; char ** hdrlist; char * user; char * pwd;
12041     char array; char * local; char * remote; int stdio;
12042 #endif /* CK_ANSIC */
12043 {
12044     char * request = NULL;
12045     int    i, j, len = 0, hdcnt = 0, rc = 0;
12046     int    ch;
12047     int    http_fnd = 0;
12048     char   buf[HTTPBUFLEN], *p;
12049     int    nullline;
12050     time_t mod_t;
12051     time_t srv_t;
12052     time_t local_t;
12053     char passwd[64];
12054     char b64in[128];
12055     char b64out[256];
12056     char * headers[HTTPHEADCNT];
12057     int  closecon = 0;
12058     int  chunked = 0;
12059     int  zfile = 0;
12060     int  first = 1;
12061
12062     if (httpfd == -1)
12063       return(-1);
12064
12065     if (array) {
12066         for (i = 0; i < HTTPHEADCNT; i++)
12067           headers[i] = NULL;
12068     }
12069     len = 10;                            /* INDEX */
12070     len += strlen(HTTP_VERSION);
12071     len += strlen(remote);
12072     len += 16;
12073
12074     if ( hdrlist ) {
12075         for (i = 0; hdrlist[i]; i++)
12076             len += strlen(hdrlist[i]) + 2;
12077     }
12078     len += strlen(http_host_port) + 8;
12079
12080     if (agent)
12081         len += 13 + strlen(agent);
12082     if (user) {
12083         if (!pwd) {
12084             readpass("Password: ",passwd,64);
12085             pwd = passwd;
12086         }
12087         ckmakmsg(b64in,sizeof(b64in),user,":",pwd,NULL);
12088         j = b8tob64(b64in,strlen(b64in),b64out,256);
12089         memset(pwd,0,strlen(pwd));
12090         if (j < 0)
12091           return(-1);
12092         b64out[j] = '\0';
12093         len += j + 24;
12094     }
12095 #ifdef HTTP_CLOSE
12096     len += 19;                          /* Connection: close */
12097 #endif
12098     len += 3;                           /* blank line + null */
12099
12100     request = malloc(len);
12101     if (!request)
12102       return(-1);
12103
12104     sprintf(request,"INDEX %s\r\n",HTTP_VERSION);
12105     ckstrncat(request,"Host: ", len);
12106     ckstrncat(request,http_host_port, len);
12107     ckstrncat(request,"\r\n",len);
12108     if (agent) {
12109         ckstrncat(request,"User-agent: ",len);
12110         ckstrncat(request,agent,len);
12111         ckstrncat(request,"\r\n",len);
12112     }
12113     if (user) {
12114         ckstrncat(request,"Authorization: Basic ",len);
12115         ckstrncat(request,b64out,len);
12116         ckstrncat(request,"\r\n",len);
12117     }
12118     if ( hdrlist ) {
12119         for (i = 0; hdrlist[i]; i++) {
12120             ckstrncat(request,hdrlist[i],len);
12121             ckstrncat(request,"\r\n",len);
12122         }
12123     }
12124 #ifdef HTTP_CLOSE
12125     ckstrncat(request,"Connection: close\r\n",len);
12126 #endif
12127     ckstrncat(request,"\r\n",len);
12128   indexreq:
12129     if (http_tol((CHAR *)request,strlen(request)) < 0)
12130     {
12131         http_close();
12132         if ( first ) {
12133             first--;
12134             http_reopen();
12135             goto indexreq;
12136         }
12137         rc = -1;
12138         goto indexexit;
12139     }
12140
12141     /* Process the headers */
12142     local_t = time(NULL);
12143     nullline = 0;
12144     i = 0;
12145     len = -1;
12146     while (!nullline && (ch = http_inc(0)) >= 0 && i < HTTPBUFLEN) {
12147         buf[i] = ch;
12148         if (buf[i] == 10) {             /* found end of line */
12149             if (i > 0 && buf[i-1] == 13)
12150               i--;
12151             if (i < 1)
12152               nullline = 1;
12153             buf[i] = '\0';
12154             if (array && !nullline && hdcnt < HTTPHEADCNT)
12155               makestr(&headers[hdcnt++],buf);
12156             if (!ckstrcmp(buf,"HTTP",4,0)) {
12157                 http_fnd = 1;
12158                 j = ckindex(" ",buf,0,0,0);
12159                 p = &buf[j];
12160                 while (isspace(*p))
12161                   p++;
12162                 switch ( p[0] ) {
12163                   case '1':             /* Informational message */
12164                     break;
12165                   case '2':             /* Success */
12166                     break;
12167                   case '3':             /* Redirection */
12168                   case '4':             /* Client failure */
12169                   case '5':             /* Server failure */
12170                   default:              /* Unknown */
12171                     if (!quiet)
12172                       printf("Failure: Server reports %s\n",p);
12173                     rc = -1;
12174                 }
12175                 http_set_code_reply(p);
12176             } else if ( !nullline ) {
12177                 if (!ckstrcmp(buf,"Connection:",11,0)) {
12178                     if ( ckindex("close",buf,11,0,0) != 0 )
12179                         closecon = 1;
12180                 } else if (!ckstrcmp(buf,"Content-Length:",15,0)) {
12181                     len = atoi(&buf[16]);
12182                 } else if (!ckstrcmp(buf,"Transfer-Encoding:",18,0)) {
12183                     if ( ckindex("chunked",buf,18,0,0) != 0 )
12184                         chunked = 1;
12185                     debug(F101,"http_index chunked","",chunked);
12186                 }
12187                 printf("%s\n",buf);
12188             }
12189             i = 0;
12190         } else {
12191             i++;
12192         }
12193     }
12194
12195     if (ch < 0 && first) {
12196         first--;
12197         http_close();
12198         http_reopen();
12199         goto indexreq;
12200     }
12201     if ( http_fnd == 0 ) {
12202         rc = -1;
12203         closecon = 1;
12204         goto indexexit;
12205     }
12206
12207     /* Now we have the contents of the file */
12208     if ( local && local[0] ) {
12209         if (zopeno(ZOFILE,local,NULL,NULL))
12210             zfile = 1;
12211         else
12212             rc = -1;
12213     }
12214
12215     if ( chunked ) {
12216         while ((len = http_get_chunk_len()) > 0) {
12217             while (len && (ch = http_inc(0)) >= 0) {
12218                 len--;
12219                 if ( zfile )
12220                     zchout(ZOFILE,(CHAR)ch);
12221                 if ( stdio )
12222                     conoc((CHAR)ch);
12223             }
12224             if ((ch = http_inc(0)) != CR)
12225                 break;
12226             if ((ch = http_inc(0)) != LF)
12227                 break;
12228         }
12229     } else {
12230         while (len && (ch = http_inc(0)) >= 0) {
12231             len--;
12232             if ( zfile )
12233                 zchout(ZOFILE,(CHAR)ch);
12234             if ( stdio )
12235                 conoc((CHAR)ch);
12236         }
12237     }
12238
12239     if ( zfile )
12240         zclose(ZOFILE);
12241
12242     if ( chunked ) {            /* Parse Trailing Headers */
12243         nullline = 0;
12244         while (!nullline && (ch = http_inc(0)) >= 0 && i < HTTPBUFLEN) {
12245             buf[i] = ch;
12246             if ( buf[i] == 10 ) { /* found end of line */
12247                 if (i > 0 && buf[i-1] == 13)
12248                   i--;
12249                 if (i < 1)
12250                   nullline = 1;
12251                 buf[i] = '\0';
12252                 if (array && !nullline && hdcnt < HTTPHEADCNT)
12253                     makestr(&headers[hdcnt++],buf);
12254                 if (!ckstrcmp(buf,"Connection:",11,0)) {
12255                     if ( ckindex("close",buf,11,0,0) != 0 )
12256                         closecon = 1;
12257                 }
12258                 i = 0;
12259             } else {
12260                 i++;
12261             }
12262         }
12263     }
12264     rc = 0;
12265
12266   indexexit:
12267     if (array)
12268       http_mkarray(headers,hdcnt,array);
12269
12270     if (closecon)
12271         http_close();
12272     free(request);
12273     for (i = 0; i < hdcnt; i++) {
12274         if (headers[i])
12275           free(headers[i]);
12276     }
12277     return(rc);
12278 }
12279
12280 int
12281 #ifdef CK_ANSIC
12282 http_put(char * agent, char ** hdrlist, char * mime, char * user,
12283          char * pwd, char array, char * local, char * remote,
12284          char * dest, int stdio)
12285 #else
12286 http_put(agent, hdrlist, mime, user, pwd, array, local, remote, dest, stdio)
12287     char * agent; char ** hdrlist; char * mime; char * user;
12288     char * pwd; char array; char * local; char * remote; char * dest;
12289     int stdio;
12290 #endif /* CK_ANSIC */
12291 {
12292     char * request=NULL;
12293     int    i, j, len = 0, hdcnt = 0, rc = 0;
12294     int    ch;
12295     int    http_fnd = 0;
12296     char   buf[HTTPBUFLEN], *p;
12297     int    nullline;
12298     time_t mod_t;
12299     time_t srv_t;
12300     time_t local_t;
12301     char passwd[64];
12302     char b64in[128];
12303     char b64out[256];
12304     int  filelen;
12305     char * headers[HTTPHEADCNT];
12306     int  closecon = 0;
12307     int  chunked = 0;
12308     int  first = 1;
12309     int  zfile = 0;
12310
12311     if (httpfd == -1)
12312       return(-1);
12313     if (!mime) mime = "";
12314     if (!remote) remote = "";
12315     if (!local) local = "";
12316     if (!*local) return(-1);
12317
12318     if (array) {
12319         for (i = 0; i < HTTPHEADCNT; i++)
12320           headers[i] = NULL;
12321     }
12322     filelen = zchki(local);
12323     if (filelen < 0)
12324       return(-1);
12325
12326     /* Compute length of request header */
12327     len = 8;                            /* PUT */
12328     len += strlen(HTTP_VERSION);
12329     len += strlen(remote);
12330     len += 16;
12331
12332     if ( hdrlist ) {
12333         for (i = 0; hdrlist[i]; i++)
12334             len += strlen(hdrlist[i]) + 2;
12335     }
12336     len += strlen(http_host_port) + 8;
12337
12338     if (agent)
12339       len += 13 + strlen(agent);
12340     if (user) {
12341         if (!pwd) {
12342             readpass("Password: ",passwd,64);
12343             pwd = passwd;
12344         }
12345         ckmakmsg(b64in,sizeof(b64in),user,":",pwd,NULL);
12346         j = b8tob64(b64in,strlen(b64in),b64out,256);
12347         memset(pwd,0,strlen(pwd));
12348         if (j < 0)
12349           return(-1);
12350         b64out[j] = '\0';
12351         len += j + 24;
12352     }
12353     len += 16 + strlen(mime);           /* Content-type: */
12354     len += 32;                          /* Content-length: */
12355     len += 32;                          /* Date: */
12356 #ifdef HTTP_CLOSE
12357     len += 19;                          /* Connection: close */
12358 #endif
12359     len += 3;                           /* blank line + null */
12360
12361     request = malloc(len);
12362     if (!request)
12363       return(-1);
12364
12365     sprintf(request,"PUT %s %s\r\n",remote,HTTP_VERSION);
12366     ckstrncat(request,"Date: ",len);
12367 #ifdef CMDATE2TM
12368     ckstrncat(request,http_now(),len);
12369 #else
12370     ckstrncat(request,...,len);
12371 #endif /* CMDATE2TM */
12372     ckstrncat(request,"\r\n",len);
12373     ckstrncat(request,"Host: ", len);
12374     ckstrncat(request,http_host_port, len);
12375     ckstrncat(request,"\r\n",len);
12376     if (agent) {
12377         ckstrncat(request,"User-agent: ",len);
12378         ckstrncat(request,agent,len);
12379         ckstrncat(request,"\r\n",len);
12380     }
12381     if (user) {
12382         ckstrncat(request,"Authorization: Basic ",len);
12383         ckstrncat(request,b64out,len);
12384         ckstrncat(request,"\r\n",len);
12385     }
12386     if ( hdrlist ) {
12387         for (i = 0; hdrlist[i]; i++) {
12388             ckstrncat(request,hdrlist[i],len);
12389             ckstrncat(request,"\r\n",len);
12390         }
12391     }
12392     ckstrncat(request,"Content-type: ",len);
12393     ckstrncat(request,mime,len);
12394     ckstrncat(request,"\r\n",len);
12395     sprintf(buf,"Content-length: %d\r\n",filelen); /* safe */
12396     ckstrncat(request,buf,len);
12397 #ifdef HTTP_CLOSE
12398     ckstrncat(request,"Connection: close\r\n",len);
12399 #endif
12400     ckstrncat(request,"\r\n",len);
12401
12402     /* Now we have the contents of the file */
12403     if (zopeni(ZIFILE,local)) {
12404
12405       putreq:                           /* Send request */
12406         if (http_tol((CHAR *)request,strlen(request)) <= 0) {
12407             http_close();
12408             if ( first ) {
12409                 first--;
12410                 http_reopen();
12411                 goto putreq;
12412             }
12413             zclose(ZIFILE);
12414             rc = -1;
12415             goto putexit;
12416         }
12417         /* Request headers have been sent */
12418
12419         i = 0;
12420         while (zchin(ZIFILE,&ch) == 0) {
12421             buf[i++] = ch;
12422             if (i == HTTPBUFLEN) {
12423                 if (http_tol((CHAR *)buf,HTTPBUFLEN) <= 0) {
12424                     http_close();
12425                     if ( first ) {
12426                         first--;
12427                         http_reopen();
12428                         goto putreq;
12429                     }
12430                 }
12431                 i = 0;
12432             }
12433         }
12434         if (i > 0) {
12435             if (http_tol((CHAR *)buf,i) < 0) {
12436                 http_close();
12437                 if ( first ) {
12438                     first--;
12439                     http_reopen();
12440                     goto putreq;
12441                 }
12442             }
12443         }
12444         zclose(ZIFILE);
12445
12446         /* Process the response headers */
12447         local_t = time(NULL);
12448         nullline = 0;
12449         i = 0;
12450         len = -1;
12451         while (!nullline && (ch = http_inc(0)) >= 0 && i < HTTPBUFLEN) {
12452             buf[i] = ch;
12453             if (buf[i] == 10) {         /* found end of line */
12454                 if (i > 0 && buf[i-1] == 13)
12455                   i--;
12456                 if (i < 1)
12457                   nullline = 1;
12458                 buf[i] = '\0';
12459                 if (array && !nullline && hdcnt < HTTPHEADCNT)
12460                   makestr(&headers[hdcnt++],buf);
12461                 if (!ckstrcmp(buf,"HTTP",4,0)) {
12462                     http_fnd = 1;
12463                     j = ckindex(" ",buf,0,0,0);
12464                     p = &buf[j];
12465                     while (isspace(*p))
12466                       p++;
12467                     switch (p[0]) {
12468                       case '1':         /* Informational message */
12469                         break;
12470                       case '2':         /* Success */
12471                         break;
12472                       case '3':         /* Redirection */
12473                       case '4':         /* Client failure */
12474                       case '5':         /* Server failure */
12475                       default:          /* Unknown */
12476                         if (!quiet)
12477                           printf("Failure: Server reports %s\n",p);
12478                         rc = -1;
12479                     }
12480                     http_set_code_reply(p);
12481                 } else {
12482                     if (!ckstrcmp(buf,"Connection:",11,0)) {
12483                         if ( ckindex("close",buf,11,0,0) != 0 )
12484                             closecon = 1;
12485                     } else if (!ckstrcmp(buf,"Content-Length:",15,0)) {
12486                         len = atoi(&buf[16]);
12487                     } else if (!ckstrcmp(buf,"Transfer-Encoding:",18,0)) {
12488                         if ( ckindex("chunked",buf,18,0,0) != 0 )
12489                             chunked = 1;
12490                         debug(F101,"http_put chunked","",chunked);
12491                     }
12492                     if ( stdio )
12493                         printf("%s\n",buf);
12494                 }
12495                 i = 0;
12496             } else {
12497                 i++;
12498             }
12499         }
12500         if (ch < 0 && first) {
12501             first--;
12502             http_close();
12503             http_reopen();
12504             goto putreq;
12505         }
12506         if ( http_fnd == 0 ) {
12507             closecon = 1;
12508             rc = -1;
12509             goto putexit;
12510         }
12511
12512         /* Any response data? */
12513         if ( dest && dest[0] ) {
12514             if (zopeno(ZOFILE,dest,NULL,NULL))
12515                 zfile = 1;
12516             else
12517                 rc = -1;
12518         }
12519
12520         if ( chunked ) {
12521             while ((len = http_get_chunk_len()) > 0) {
12522                 while (len && (ch = http_inc(0)) >= 0) {
12523                     len--;
12524                     if ( zfile )
12525                         zchout(ZOFILE,(CHAR)ch);
12526                     if ( stdio )
12527                         conoc((CHAR)ch);
12528                 }
12529                 if ((ch = http_inc(0)) != CR)
12530                     break;
12531                 if ((ch = http_inc(0)) != LF)
12532                     break;
12533             }
12534         } else {
12535             while (len && (ch = http_inc(0)) >= 0) {
12536                 len--;
12537                 if ( zfile )
12538                     zchout(ZOFILE,(CHAR)ch);
12539                 if ( stdio )
12540                     conoc((CHAR)ch);
12541             }
12542         }
12543
12544         if ( zfile )
12545             zclose(ZOFILE);
12546
12547         if ( chunked ) {            /* Parse Trailing Headers */
12548             nullline = 0;
12549             while (!nullline && (ch = http_inc(0)) >= 0 && i < HTTPBUFLEN) {
12550                 buf[i] = ch;
12551                 if ( buf[i] == 10 ) { /* found end of line */
12552                     if (i > 0 && buf[i-1] == 13)
12553                       i--;
12554                     if (i < 1)
12555                       nullline = 1;
12556                     buf[i] = '\0';
12557                     if (array && !nullline && hdcnt < HTTPHEADCNT)
12558                         makestr(&headers[hdcnt++],buf);
12559                     if (!ckstrcmp(buf,"Connection:",11,0)) {
12560                         if ( ckindex("close",buf,11,0,0) != 0 )
12561                             closecon = 1;
12562                     }
12563                     i = 0;
12564                 } else {
12565                     i++;
12566                 }
12567             }
12568         }
12569     } else {
12570         rc = -1;
12571     }
12572
12573   putexit:
12574     if ( array )
12575         http_mkarray(headers,hdcnt,array);
12576
12577     if (closecon)
12578         http_close();
12579     free(request);
12580     for (i = 0; i < hdcnt; i++) {
12581         if (headers[i])
12582           free(headers[i]);
12583     }
12584     return(rc);
12585 }
12586
12587 int
12588 #ifdef CK_ANSIC
12589 http_delete(char * agent, char ** hdrlist, char * user,
12590           char * pwd, char array, char * remote)
12591 #else
12592 http_delete(agent, hdrlist, user, pwd, array, remote)
12593     char * agent; char ** hdrlist; char * user;
12594     char * pwd; char array; char * remote;
12595 #endif /* CK_ANSIC */
12596 {
12597     char * request=NULL;
12598     int    i, j, len = 0, hdcnt = 0, rc = 0;
12599     int    ch;
12600     int    http_fnd = 0;
12601     char   buf[HTTPBUFLEN], *p;
12602     int    nullline;
12603     time_t mod_t;
12604     time_t srv_t;
12605     time_t local_t;
12606     char passwd[64];
12607     char b64in[128];
12608     char b64out[256];
12609     char * headers[HTTPHEADCNT];
12610     int  closecon = 0;
12611     int  chunked = 0;
12612     int  first = 1;
12613
12614     if (httpfd == -1)
12615       return(-1);
12616
12617     if (array) {
12618         for (i = 0; i < HTTPHEADCNT; i++)
12619           headers[i] = NULL;
12620     }
12621
12622     /* Compute length of request header */
12623     len = 11;                            /* DELETE */
12624     len += strlen(HTTP_VERSION);
12625     len += strlen(remote);
12626     len += 16;
12627
12628     if ( hdrlist ) {
12629         for (i = 0; hdrlist[i]; i++)
12630             len += strlen(hdrlist[i]) + 2;
12631     }
12632     len += strlen(http_host_port) + 8;
12633
12634     if (agent)
12635       len += 13 + strlen(agent);
12636     if (user) {
12637         if (!pwd) {
12638             readpass("Password: ",passwd,64);
12639             pwd = passwd;
12640         }
12641         ckmakmsg(b64in,sizeof(b64in),user,":",pwd,NULL);
12642         j = b8tob64(b64in,strlen(b64in),b64out,256);
12643         memset(pwd,0,strlen(pwd));
12644         if (j < 0)
12645           return(-1);
12646         b64out[j] = '\0';
12647         len += j + 24;
12648     }
12649     len += 32;                          /* Date: */
12650 #ifdef HTTP_CLOSE
12651     len += 19;                          /* Connection: close */
12652 #endif
12653     len += 3;                           /* blank line + null */
12654
12655     request = malloc(len);
12656     if (!request)
12657       return(-1);
12658
12659     sprintf(request,"DELETE %s %s\r\n",remote,HTTP_VERSION);
12660     ckstrncat(request,"Date: ",len);
12661 #ifdef CMDATE2TM
12662     ckstrncat(request,http_now(),len);
12663 #else
12664     ckstrncat(request,...,len);
12665 #endif /* CMDATE2TM */
12666     ckstrncat(request,"\r\n",len);
12667     ckstrncat(request,"Host: ", len);
12668     ckstrncat(request,http_host_port, len);
12669     ckstrncat(request,"\r\n",len);
12670     if (agent) {
12671         ckstrncat(request,"User-agent: ",len);
12672         ckstrncat(request,agent,len);
12673         ckstrncat(request,"\r\n",len);
12674     }
12675     if (user) {
12676         ckstrncat(request,"Authorization: Basic ",len);
12677         ckstrncat(request,b64out,len);
12678         ckstrncat(request,"\r\n",len);
12679     }
12680     if ( hdrlist ) {
12681         for (i = 0; hdrlist[i]; i++) {
12682             ckstrncat(request,hdrlist[i],len);
12683             ckstrncat(request,"\r\n",len);
12684         }
12685     }
12686 #ifdef HTTP_CLOSE
12687     ckstrncat(request,"Connection: close\r\n",len);
12688 #endif
12689     ckstrncat(request,"\r\n",len);
12690   delreq:
12691     if (http_tol((CHAR *)request,strlen(request)) < 0)
12692     {
12693         http_close();
12694         if ( first ) {
12695             first--;
12696             http_reopen();
12697             goto delreq;
12698         }
12699         rc = -1;
12700         goto delexit;
12701     }
12702
12703     /* Process the response headers */
12704     local_t = time(NULL);
12705     nullline = 0;
12706     i = 0;
12707     len = -1;
12708     while (!nullline && (ch = http_inc(0)) >= 0 && i < HTTPBUFLEN) {
12709         buf[i] = ch;
12710         if (buf[i] == 10) {         /* found end of line */
12711             if (i > 0 && buf[i-1] == 13)
12712               i--;
12713             if (i < 1)
12714               nullline = 1;
12715             buf[i] = '\0';
12716             if (array && !nullline && hdcnt < HTTPHEADCNT)
12717                 makestr(&headers[hdcnt++],buf);
12718             if (!ckstrcmp(buf,"HTTP",4,0)) {
12719                 http_fnd = 1;
12720                 j = ckindex(" ",buf,0,0,0);
12721                 p = &buf[j];
12722                 while (isspace(*p))
12723                   p++;
12724                 switch (p[0]) {
12725                   case '1':             /* Informational message */
12726                     break;
12727                   case '2':             /* Success */
12728                     break;
12729                   case '3':             /* Redirection */
12730                   case '4':             /* Client failure */
12731                   case '5':             /* Server failure */
12732                   default:              /* Unknown */
12733                     if (!quiet)
12734                       printf("Failure: Server reports %s\n",p);
12735                     rc = -1;
12736                 }
12737                 http_set_code_reply(p);
12738             } else {
12739                 if (!ckstrcmp(buf,"Connection:",11,0)) {
12740                     if ( ckindex("close",buf,11,0,0) != 0 )
12741                         closecon = 1;
12742                 } else if (!ckstrcmp(buf,"Content-Length:",15,0)) {
12743                     len = atoi(&buf[16]);
12744                 } else if (!ckstrcmp(buf,"Transfer-Encoding:",18,0)) {
12745                     if ( ckindex("chunked",buf,18,0,0) != 0 )
12746                         chunked = 1;
12747                     debug(F101,"http_delete chunked","",chunked);
12748                 }
12749                 printf("%s\n",buf);
12750             }
12751             i = 0;
12752         } else {
12753             i++;
12754         }
12755     }
12756     if (ch < 0 && first) {
12757         first--;
12758         http_close();
12759         http_reopen();
12760         goto delreq;
12761     }
12762     if ( http_fnd == 0 ) {
12763         rc = -1;
12764         closecon = 1;
12765         goto delexit;
12766     }
12767
12768     /* Any response data? */
12769     if ( chunked ) {
12770         while ((len = http_get_chunk_len()) > 0) {
12771             while (len && (ch = http_inc(0)) >= 0) {
12772                 len--;
12773                 conoc((CHAR)ch);
12774             }
12775             if ((ch = http_inc(0)) != CR)
12776                 break;
12777             if ((ch = http_inc(0)) != LF)
12778                 break;
12779         }
12780     } else {
12781         while (len && (ch = http_inc(0)) >= 0) {
12782             len--;
12783             conoc((CHAR)ch);
12784         }
12785     }
12786
12787     if ( chunked ) {            /* Parse Trailing Headers */
12788         nullline = 0;
12789         while (!nullline && (ch = http_inc(0)) >= 0 && i < HTTPBUFLEN) {
12790             buf[i] = ch;
12791             if ( buf[i] == 10 ) { /* found end of line */
12792                 if (i > 0 && buf[i-1] == 13)
12793                   i--;
12794                 if (i < 1)
12795                   nullline = 1;
12796                 buf[i] = '\0';
12797                 if (array && !nullline && hdcnt < HTTPHEADCNT)
12798                     makestr(&headers[hdcnt++],buf);
12799                 if (!ckstrcmp(buf,"Connection:",11,0)) {
12800                     if ( ckindex("close",buf,11,0,0) != 0 )
12801                         closecon = 1;
12802                 }
12803                 i = 0;
12804             } else {
12805                 i++;
12806             }
12807         }
12808     }
12809
12810   delexit:
12811     if (array)
12812         http_mkarray(headers,hdcnt,array);
12813
12814     if (closecon)
12815         http_close();
12816     free(request);
12817     for (i = 0; i < hdcnt; i++) {
12818         if (headers[i])
12819           free(headers[i]);
12820     }
12821     return(rc);
12822 }
12823
12824 int
12825 #ifdef CK_ANSIC
12826 http_post(char * agent, char ** hdrlist, char * mime, char * user,
12827           char * pwd, char array, char * local, char * remote,
12828           char * dest, int stdio)
12829 #else
12830 http_post(agent, hdrlist, mime, user, pwd, array, local, remote, dest,
12831           stdio)
12832     char * agent; char ** hdrlist; char * mime; char * user;
12833     char * pwd; char array; char * local; char * remote; char * dest;
12834     int stdio;
12835 #endif /* CK_ANSIC */
12836 {
12837     char * request=NULL;
12838     int    i, j, len = 0, hdcnt = 0, rc = 0;
12839     int    ch;
12840     int    http_fnd = 0;
12841     char   buf[HTTPBUFLEN], *p;
12842     int    nullline;
12843     time_t mod_t;
12844     time_t srv_t;
12845     time_t local_t;
12846     char passwd[64];
12847     char b64in[128];
12848     char b64out[256];
12849     int  filelen;
12850     char * headers[HTTPHEADCNT];
12851     int  closecon = 0;
12852     int  chunked = 0;
12853     int  zfile = 0;
12854     int  first = 1;
12855
12856     if (httpfd == -1)
12857       return(-1);
12858
12859     if (array) {
12860         for (i = 0; i < HTTPHEADCNT; i++)
12861           headers[i] = NULL;
12862     }
12863     filelen = zchki(local);
12864     if (filelen < 0)
12865       return(-1);
12866
12867     /* Compute length of request header */
12868     len = 9;                            /* POST */
12869     len += strlen(HTTP_VERSION);
12870     len += strlen(remote);
12871     len += 16;
12872
12873     if ( hdrlist ) {
12874         for (i = 0; hdrlist[i]; i++)
12875             len += strlen(hdrlist[i]) + 2;
12876     }
12877     len += strlen(http_host_port) + 8;
12878
12879     if (agent)
12880       len += 13 + strlen(agent);
12881     if (user) {
12882         if (!pwd) {
12883             readpass("Password: ",passwd,64);
12884             pwd = passwd;
12885         }
12886         ckmakmsg(b64in,sizeof(b64in),user,":",pwd,NULL);
12887         j = b8tob64(b64in,strlen(b64in),b64out,256);
12888         memset(pwd,0,strlen(pwd));
12889         if (j < 0)
12890           return(-1);
12891         b64out[j] = '\0';
12892         len += j + 24;
12893     }
12894     len += 16 + strlen(mime);           /* Content-type: */
12895     len += 32;                          /* Content-length: */
12896     len += 32;                          /* Date: */
12897 #ifdef HTTP_CLOSE
12898     len += 19;                          /* Connection: close */
12899 #endif
12900     len += 3;                           /* blank line + null */
12901
12902     request = malloc(len);
12903     if (!request)
12904       return(-1);
12905
12906     sprintf(request,"POST %s %s\r\n",remote,HTTP_VERSION);
12907     ckstrncat(request,"Date: ",len);
12908     ckstrncat(request,http_now(),len);
12909     ckstrncat(request,"\r\n",len);
12910     ckstrncat(request,"Host: ", len);
12911     ckstrncat(request,http_host_port, len);
12912     ckstrncat(request,"\r\n",len);
12913     if (agent) {
12914         ckstrncat(request,"User-agent: ",len);
12915         ckstrncat(request,agent,len);
12916         ckstrncat(request,"\r\n",len);
12917     }
12918     if (user) {
12919         ckstrncat(request,"Authorization: Basic ",len);
12920         ckstrncat(request,b64out,len);
12921         ckstrncat(request,"\r\n",len);
12922     }
12923     if ( hdrlist ) {
12924         for (i = 0; hdrlist[i]; i++) {
12925             ckstrncat(request,hdrlist[i],len);
12926             ckstrncat(request,"\r\n",len);
12927         }
12928     }
12929     ckstrncat(request,"Content-type: ",len);
12930     ckstrncat(request,mime,len);
12931     ckstrncat(request,"\r\n",len);
12932 #ifdef HTTP_CLOSE
12933     ckstrncat(request,"Connection: close\r\n",len);
12934 #endif
12935     sprintf(buf,"Content-length: %d\r\n",filelen); /* safe */
12936     ckstrncat(request,buf,len);
12937     ckstrncat(request,"\r\n",len);
12938 #ifdef COMMENT
12939     /* This is apparently a mistake - the previous ckstrncat() already  */
12940     /* appended a blank line to the request.  There should only be one. */
12941     /* Servers are not required by RFC 2616 to ignore extraneous empty  */
12942     /* lines.  -fdc, 28 Aug 2005. */
12943     ckstrncat(request,"\r\n",len);
12944 #endif  /* COMMENT */
12945
12946     /* Now we have the contents of the file */
12947   postopen:
12948     if (zopeni(ZIFILE,local)) {
12949       postreq:
12950         if (http_tol((CHAR *)request,strlen(request)) < 0)
12951         {
12952             http_close();
12953             if ( first ) {
12954                 first--;
12955                 http_reopen();
12956                 goto postreq;
12957             }
12958             rc = -1;
12959             zclose(ZIFILE);
12960             goto postexit;
12961         }
12962
12963         i = 0;
12964         while (zchin(ZIFILE,&ch) == 0) {
12965             buf[i++] = ch;
12966             if (i == HTTPBUFLEN) {
12967                 http_tol((CHAR *)buf,HTTPBUFLEN);
12968                 i = 0;
12969             }
12970         }
12971         if (i > 0)
12972           http_tol((CHAR *)buf,HTTPBUFLEN);
12973         zclose(ZIFILE);
12974
12975         /* Process the response headers */
12976         local_t = time(NULL);
12977         nullline = 0;
12978         i = 0;
12979         len = -1;
12980         while (!nullline && (ch = http_inc(0)) >= 0 && i < HTTPBUFLEN) {
12981             buf[i] = ch;
12982             if (buf[i] == 10) {         /* found end of line */
12983                 if (i > 0 && buf[i-1] == 13)
12984                   i--;
12985                 if (i < 1)
12986                   nullline = 1;
12987                 buf[i] = '\0';
12988                 if (array && !nullline && hdcnt < HTTPHEADCNT)
12989                   makestr(&headers[hdcnt++],buf);
12990                 if (!ckstrcmp(buf,"HTTP",4,0)) {
12991                     http_fnd = 1;
12992                     j = ckindex(" ",buf,0,0,0);
12993                     p = &buf[j];
12994                     while (isspace(*p))
12995                       p++;
12996                     switch (p[0]) {
12997                       case '1':         /* Informational message */
12998                         break;
12999                       case '2':         /* Success */
13000                         break;
13001                       case '3':         /* Redirection */
13002                       case '4':         /* Client failure */
13003                       case '5':         /* Server failure */
13004                       default:          /* Unknown */
13005                         if (!quiet)
13006                           printf("Failure: Server reports %s\n",p);
13007                         rc = -1;
13008                     }
13009                     http_set_code_reply(p);
13010                 } else {
13011                     if (!ckstrcmp(buf,"Connection:",11,0)) {
13012                         if ( ckindex("close",buf,11,0,0) != 0 )
13013                             closecon = 1;
13014                     } else if (!ckstrcmp(buf,"Content-Length:",15,0)) {
13015                         len = atoi(&buf[16]);
13016                     } else if (!ckstrcmp(buf,"Transfer-Encoding:",18,0)) {
13017                         if ( ckindex("chunked",buf,18,0,0) != 0 )
13018                             chunked = 1;
13019                         debug(F101,"http_post chunked","",chunked);
13020                     }
13021                     if (stdio)
13022                         printf("%s\n",buf);
13023                 }
13024                 i = 0;
13025             } else {
13026                 i++;
13027             }
13028         }
13029         if (ch < 0 && first) {
13030             first--;
13031             http_close();
13032             http_reopen();
13033             goto postopen;
13034         }
13035         if (http_fnd == 0) {
13036             rc = -1;
13037             closecon = 1;
13038             goto postexit;
13039         }
13040
13041         /* Any response data? */
13042         if ( dest && dest[0] ) {
13043             if (zopeno(ZOFILE,dest,NULL,NULL))
13044                 zfile = 1;
13045             else
13046                 rc = -1;
13047         }
13048
13049         if ( chunked ) {
13050             while ((len = http_get_chunk_len()) > 0) {
13051                 while (len && (ch = http_inc(0)) >= 0) {
13052                     len--;
13053                     if ( zfile )
13054                         zchout(ZOFILE,(CHAR)ch);
13055                     if ( stdio )
13056                         conoc((CHAR)ch);
13057                 }
13058                 if ((ch = http_inc(0)) != CR)
13059                     break;
13060                 if ((ch = http_inc(0)) != LF)
13061                     break;
13062             }
13063         } else {
13064             while (len && (ch = http_inc(0)) >= 0) {
13065                 len--;
13066                 if ( zfile )
13067                     zchout(ZOFILE,(CHAR)ch);
13068                 if ( stdio )
13069                     conoc((CHAR)ch);
13070             }
13071         }
13072
13073         if ( zfile )
13074             zclose(ZOFILE);
13075
13076         if ( chunked ) {            /* Parse Trailing Headers */
13077             nullline = 0;
13078             while (!nullline && (ch = http_inc(0)) >= 0 && i < HTTPBUFLEN) {
13079                 buf[i] = ch;
13080                 if ( buf[i] == 10 ) { /* found end of line */
13081                     if (i > 0 && buf[i-1] == 13)
13082                       i--;
13083                     if (i < 1)
13084                       nullline = 1;
13085                     buf[i] = '\0';
13086                     if (array && !nullline && hdcnt < HTTPHEADCNT)
13087                         makestr(&headers[hdcnt++],buf);
13088                     if (!ckstrcmp(buf,"Connection:",11,0)) {
13089                         if ( ckindex("close",buf,11,0,0) != 0 )
13090                             closecon = 1;
13091                     }
13092                     i = 0;
13093                 } else {
13094                     i++;
13095                 }
13096             }
13097         }
13098     } else {
13099         rc = -1;
13100     }
13101
13102   postexit:
13103     if (array)
13104         http_mkarray(headers,hdcnt,array);
13105     if (closecon)
13106         http_close();
13107     free(request);
13108     for (i = 0; i < hdcnt; i++) {
13109         if (headers[i])
13110           free(headers[i]);
13111     }
13112     return(rc);
13113 }
13114
13115 int
13116 #ifdef CK_ANSIC
13117 http_connect(int socket, char * agent, char ** hdrlist, char * user,
13118              char * pwd, char array, char * host_port)
13119 #else
13120 http_connect(socket, agent, hdrlist, user, pwd, array, host_port)
13121     int socket;
13122     char * agent; char ** hdrlist; char * user;
13123     char * pwd; char array; char * host_port;
13124 #endif /* CK_ANSIC */
13125 {
13126     char * request=NULL;
13127     int    i, j, len = 0, hdcnt = 0, rc = 0;
13128     int    http_fnd = 0;
13129     char   buf[HTTPBUFLEN], *p, ch;
13130     int    nullline;
13131     time_t mod_t;
13132     time_t srv_t;
13133     time_t local_t;
13134     char passwd[64];
13135     char b64in[128];
13136     char b64out[256];
13137     char * headers[HTTPHEADCNT];
13138     int    connected = 0;
13139
13140     tcp_http_proxy_errno = 0;
13141
13142     if (socket == -1)
13143       return(-1);
13144
13145     if (array) {
13146         for (i = 0; i < HTTPHEADCNT; i++)
13147           headers[i] = NULL;
13148     }
13149
13150     /* Compute length of request header */
13151     len = 12;                            /* CONNECT */
13152     len += strlen(HTTP_VERSION);
13153     len += strlen(host_port);
13154     len += (int) strlen(http_host_port) + 8;
13155     len += 16;
13156     len += strlen("Proxy-Connection: Keep-Alive\r\n");
13157     if ( hdrlist ) {
13158         for (i = 0; hdrlist[i]; i++)
13159             len += strlen(hdrlist[i]) + 2;
13160     }
13161     if (agent && agent[0])
13162       len += 13 + strlen(agent);
13163     if (user && user[0]) {
13164         if (!pwd) {
13165             readpass("Password: ",passwd,64);
13166             pwd = passwd;
13167         }
13168         ckmakmsg(b64in,sizeof(b64in),user,":",pwd,NULL);
13169         j = b8tob64(b64in,strlen(b64in),b64out,256);
13170         memset(pwd,0,strlen(pwd));
13171         if (j < 0)
13172           return(-1);
13173         b64out[j] = '\0';
13174         len += j + 72;
13175     }
13176     len += 32;                          /* Date: */
13177     len += 3;                           /* blank line + null */
13178
13179     request = malloc(len);
13180     if (!request)
13181       return(-1);
13182
13183     sprintf(request,"CONNECT %s %s\r\n",host_port,HTTP_VERSION);
13184     ckstrncat(request,"Date: ",len);
13185 #ifdef CMDATE2TM
13186     ckstrncat(request,http_now(),len);
13187 #else
13188     strcat(request,...);
13189 #endif /* CMDATE2TM */
13190     ckstrncat(request,"\r\n",len);
13191     ckstrncat(request,"Host: ", len);
13192     ckstrncat(request,http_host_port, len);
13193     ckstrncat(request,"\r\n",len);
13194     if (agent && agent[0]) {
13195         ckstrncat(request,"User-agent: ",len);
13196         ckstrncat(request,agent,len);
13197         ckstrncat(request,"\r\n",len);
13198     }
13199     if (user && user[0]) {
13200         ckstrncat(request,"Proxy-authorization: Basic ",len);
13201         ckstrncat(request,b64out,len);
13202         ckstrncat(request,"\r\n",len);
13203         ckstrncat(request,"Extension: Security/Remote-Passphrase\r\n",len);
13204     }
13205     ckstrncat(request,"Proxy-Connection: Keep-Alive\r\n",len);
13206     if ( hdrlist ) {
13207         for (i = 0; hdrlist[i]; i++) {
13208             ckstrncat(request,hdrlist[i],len);
13209             ckstrncat(request,"\r\n",len);
13210         }
13211     }
13212     ckstrncat(request,"\r\n",len);
13213     len = strlen(request);
13214
13215 #ifdef TCPIPLIB
13216     /* Send request */
13217     if (socket_write(socket,(CHAR *)request,strlen(request)) < 0) {
13218       rc = -1;
13219       goto connexit;
13220     }
13221 #else
13222     if (write(socket,(CHAR *)request,strlen(request)) < 0) { /* Send request */
13223         rc = -1;
13224         goto connexit;
13225     }
13226 #endif /* TCPIPLIB */
13227
13228     /* Process the response headers */
13229     local_t = time(NULL);
13230     nullline = 0;
13231     i = 0;
13232     while (!nullline &&
13233 #ifdef TCPIPLIB
13234            (socket_read(socket,&ch,1) == 1) &&
13235 #else
13236            (read(socket,&ch,1) == 1) &&
13237 #endif /* TCPIPLIB */
13238            i < HTTPBUFLEN) {
13239         buf[i] = ch;
13240         if (buf[i] == 10) {         /* found end of line */
13241             if (i > 0 && buf[i-1] == 13)
13242               i--;
13243             if (i < 1)
13244               nullline = 1;
13245             buf[i] = '\0';
13246
13247             if (array && !nullline && hdcnt < HTTPHEADCNT)
13248                 makestr(&headers[hdcnt++],buf);
13249             if (!ckstrcmp(buf,"HTTP",4,0)) {
13250                 http_fnd = 1;
13251                 j = ckindex(" ",buf,0,0,0);
13252                 p = &buf[j];
13253                 while (isspace(*p))
13254                   p++;
13255                 tcp_http_proxy_errno = atoi(p);
13256                 switch (p[0]) {
13257                   case '1':             /* Informational message */
13258                     break;
13259                   case '2':             /* Success */
13260                     connected = 1;
13261                     break;
13262                   case '3':             /* Redirection */
13263                   case '4':             /* Client failure */
13264                   case '5':             /* Server failure */
13265                   default:              /* Unknown */
13266                     if (!quiet)
13267                       printf("Failure: Server reports %s\n",p);
13268                     rc = -1;
13269                 }
13270                 http_set_code_reply(p);
13271             } else {
13272                 printf("%s\n",buf);
13273             }
13274             i = 0;
13275         } else {
13276             i++;
13277         }
13278     }
13279     if ( http_fnd == 0 )
13280         rc = -1;
13281
13282     if (array)
13283         http_mkarray(headers,hdcnt,array);
13284
13285   connexit:
13286     if ( !connected ) {
13287         if ( socket == ttyfd ) {
13288             ttclos(0);
13289         }
13290         else if ( socket == httpfd ) {
13291             http_close();
13292         }
13293     }
13294
13295     free(request);
13296     for (i = 0; i < hdcnt; i++) {
13297         if (headers[i])
13298           free(headers[i]);
13299     }
13300     return(rc);
13301 }
13302 #endif /* NOHTTP */
13303
13304 #ifdef CK_DNS_SRV
13305
13306 #define INCR_CHECK(x,y) x += y; if (x > size + answer.bytes) goto dnsout
13307 #define CHECK(x,y) if (x + y > size + answer.bytes) goto dnsout
13308 #define NTOHSP(x,y) x[0] << 8 | x[1]; x += y
13309
13310 #ifndef CKQUERYTYPE
13311 #ifdef UNIXWARE
13312 #ifndef UW7
13313 #define CKQUERYTYPE CHAR
13314 #endif /* UW7 */
13315 #endif /* UNIXWARE */
13316 #endif /* CKQUERYTYPE */
13317
13318 #ifndef CKQUERYTYPE
13319 #define CKQUERYTYPE char
13320 #endif /* CKQUERYTYPE */
13321
13322 /* 1 is success, 0 is failure */
13323 int
13324 locate_srv_dns(host, service, protocol, addr_pp, naddrs)
13325     char *host;
13326     char *service;
13327     char *protocol;
13328     struct sockaddr **addr_pp;
13329     int *naddrs;
13330 {
13331     int nout, j, count;
13332     union {
13333         unsigned char bytes[2048];
13334         HEADER hdr;
13335     } answer;
13336     unsigned char *p=NULL;
13337     CKQUERYTYPE query[MAX_DNS_NAMELEN];
13338 #ifdef CK_ANSIC
13339     const char * h;
13340 #else
13341     char * h;
13342 #endif /* CK_ANSIC */
13343     struct sockaddr *addr = NULL;
13344     struct sockaddr_in *sin = NULL;
13345     struct hostent *hp = NULL;
13346     int type, class;
13347     int priority, weight, size, len, numanswers, numqueries, rdlen;
13348     unsigned short port;
13349 #ifdef CK_ANSIC
13350     const
13351 #endif /* CK_ANSIC */
13352       int hdrsize = sizeof(HEADER);
13353     struct srv_dns_entry {
13354         struct srv_dns_entry *next;
13355         int priority;
13356         int weight;
13357         unsigned short port;
13358         char *host;
13359     };
13360     struct srv_dns_entry *head = NULL;
13361     struct srv_dns_entry *srv = NULL, *entry = NULL;
13362     char * s = NULL;
13363
13364     nout = 0;
13365     addr = (struct sockaddr *) malloc(sizeof(struct sockaddr));
13366     if (addr == NULL)
13367       return 0;
13368
13369     count = 1;
13370
13371     /*
13372      * First build a query of the form:
13373      *
13374      *   service.protocol.host
13375      *
13376      * which will most likely be something like:
13377      *
13378      *   _telnet._tcp.host
13379      *
13380      */
13381     if (((int)strlen(service) + strlen(protocol) + strlen(host) + 5)
13382         > MAX_DNS_NAMELEN
13383         )
13384       goto dnsout;
13385
13386     /* Realm names don't (normally) end with ".", but if the query
13387        doesn't end with "." and doesn't get an answer as is, the
13388        resolv code will try appending the local domain.  Since the
13389        realm names are absolutes, let's stop that.
13390
13391        But only if a name has been specified.  If we are performing
13392        a search on the prefix alone then the intention is to allow
13393        the local domain or domain search lists to be expanded.
13394     */
13395     h = host + strlen (host);
13396     ckmakxmsg(query, sizeof(query), "_",service,"._",protocol,".", host,
13397               ((h > host) && (h[-1] != '.')?".":NULL),
13398                NULL,NULL,NULL,NULL,NULL);
13399
13400     size = res_search(query, C_IN, T_SRV, answer.bytes, sizeof(answer.bytes));
13401
13402     if (size < hdrsize)
13403       goto dnsout;
13404
13405     /* We got a reply - See how many answers it contains. */
13406
13407     p = answer.bytes;
13408
13409     numqueries = ntohs(answer.hdr.qdcount);
13410     numanswers = ntohs(answer.hdr.ancount);
13411
13412     p += sizeof(HEADER);
13413
13414     /*
13415      * We need to skip over all of the questions, so we have to iterate
13416      * over every query record.  dn_expand() is able to tell us the size
13417      * of compressed DNS names, so we use it.
13418      */
13419     while (numqueries--) {
13420         len = dn_expand(answer.bytes,answer.bytes+size,p,query,sizeof(query));
13421         if (len < 0)
13422           goto dnsout;
13423         INCR_CHECK(p, len + 4);
13424     }
13425
13426     /*
13427      * We're now pointing at the answer records.  Only process them if
13428      * they're actually T_SRV records (they might be CNAME records,
13429      * for instance).
13430      *
13431      * But in a DNS reply, if you get a CNAME you always get the associated
13432      * "real" RR for that CNAME.  RFC 1034, 3.6.2:
13433      *
13434      * CNAME RRs cause special action in DNS software.  When a name server
13435      * fails to find a desired RR in the resource set associated with the
13436      * domain name, it checks to see if the resource set consists of a CNAME
13437      * record with a matching class.  If so, the name server includes the CNAME
13438      * record in the response and restarts the query at the domain name
13439      * specified in the data field of the CNAME record.  The one exception to
13440      * this rule is that queries which match the CNAME type are not restarted.
13441      *
13442      * In other words, CNAMEs do not need to be expanded by the client.
13443      */
13444     while (numanswers--) {
13445
13446         /* First is the name; use dn_expand() to get the compressed size. */
13447         len = dn_expand(answer.bytes,answer.bytes+size,p,query,sizeof(query));
13448         if (len < 0)
13449           goto dnsout;
13450         INCR_CHECK(p, len);
13451
13452         CHECK(p,2);                     /* Query type */
13453         type = NTOHSP(p,2);
13454
13455         CHECK(p, 6);                    /* Query class */
13456         class = NTOHSP(p,6);            /* Also skip over 4-byte TTL */
13457
13458         CHECK(p,2);                     /* Record data length */
13459         rdlen = NTOHSP(p,2);
13460         /*
13461          * If this is an SRV record, process it.  Record format is:
13462          *
13463          * Priority
13464          * Weight
13465          * Port
13466          * Server name
13467          */
13468         if (class == C_IN && type == T_SRV) {
13469             CHECK(p,2);
13470             priority = NTOHSP(p,2);
13471             CHECK(p, 2);
13472             weight = NTOHSP(p,2);
13473             CHECK(p, 2);
13474             port = NTOHSP(p,2);
13475             len = dn_expand(answer.
13476                             bytes,
13477                             answer.bytes + size,
13478                             p,
13479                             query,
13480                             sizeof(query)
13481                             );
13482             if (len < 0)
13483               goto dnsout;
13484             INCR_CHECK(p, len);
13485             /*
13486              * We got everything.  Insert it into our list, but make sure
13487              * it's in the right order.  Right now we don't do anything
13488              * with the weight field
13489              */
13490             srv = (struct srv_dns_entry *)malloc(sizeof(struct srv_dns_entry));
13491             if (srv == NULL)
13492               goto dnsout;
13493
13494             srv->priority = priority;
13495             srv->weight = weight;
13496             srv->port = port;
13497             makestr(&s,(char *)query);  /* strdup() is not portable */
13498             srv->host = s;
13499
13500             if (head == NULL || head->priority > srv->priority) {
13501                 srv->next = head;
13502                 head = srv;
13503             } else
13504                 /*
13505                  * Confusing.  Insert an entry into this spot only if:
13506                  *  . The next person has a higher priority (lower
13507                  *    priorities are preferred), or:
13508                  *  . There is no next entry (we're at the end)
13509                  */
13510               for (entry = head; entry != NULL; entry = entry->next)
13511                 if ((entry->next &&
13512                      entry->next->priority > srv->priority) ||
13513                     entry->next == NULL) {
13514                     srv->next = entry->next;
13515                     entry->next = srv;
13516                     break;
13517                 }
13518         } else
13519           INCR_CHECK(p, rdlen);
13520     }
13521
13522     /*
13523      * Now we've got a linked list of entries sorted by priority.
13524      * Start looking up A records and returning addresses.
13525      */
13526     if (head == NULL)
13527       goto dnsout;
13528
13529     for (entry = head; entry != NULL; entry = entry->next) {
13530         hp = gethostbyname(entry->host);
13531         if (hp != 0) {
13532
13533             /* Watch out - memset() and memcpy() are not portable... */
13534
13535             switch (hp->h_addrtype) {
13536               case AF_INET:
13537                 for (j = 0; hp->h_addr_list[j]; j++) {
13538                     sin = (struct sockaddr_in *) &addr[nout++];
13539                     memset ((char *) sin, 0, sizeof (struct sockaddr));
13540                     sin->sin_family = hp->h_addrtype;
13541                     sin->sin_port = htons(entry->port);
13542                     memcpy((char *) &sin->sin_addr,
13543                            (char *) hp->h_addr_list[j],
13544                            sizeof(struct in_addr));             /* safe */
13545                     if (nout + 1 >= count) {
13546                         count += 5;
13547                         addr = (struct sockaddr *)
13548                           realloc((char *) addr,
13549                                   sizeof(struct sockaddr) * count);
13550                         if (!addr)
13551                           goto dnsout;
13552                     }
13553                 }
13554                 break;
13555               default:
13556                 break;
13557             }
13558         }
13559     }
13560     for (entry = head; entry != NULL;) {
13561         free(entry->host);
13562         entry->host = NULL;
13563         srv = entry;
13564         entry = entry->next;
13565         free(srv);
13566         srv = NULL;
13567     }
13568
13569   dnsout:
13570     if (srv)
13571       free(srv);
13572
13573     if (nout == 0) {                    /* No good servers */
13574         if (addr)
13575           free(addr);
13576         return 0;
13577     }
13578     *addr_pp = addr;
13579     *naddrs = nout;
13580     return 1;
13581 }
13582 #undef INCR_CHECK
13583 #undef CHECK
13584 #undef NTOHSP
13585
13586 #define INCR_CHECK(x, y) x += y; if (x > size + answer.bytes) \
13587                          return 0
13588 #define CHECK(x, y) if (x + y > size + answer.bytes) \
13589                          return 0
13590 #define NTOHSP(x, y) x[0] << 8 | x[1]; x += y
13591
13592 int
13593 locate_txt_rr(prefix, name, retstr)
13594     char *prefix, *name;
13595     char **retstr;
13596 {
13597     union {
13598         unsigned char bytes[2048];
13599         HEADER hdr;
13600     } answer;
13601     unsigned char *p;
13602     char host[MAX_DNS_NAMELEN], *h;
13603     int size;
13604     int type, class, numanswers, numqueries, rdlen, len;
13605
13606     /*
13607      * Form our query, and send it via DNS
13608      */
13609
13610     if (name == NULL || name[0] == '\0') {
13611         strcpy(host,prefix);
13612     } else {
13613         if ( strlen(prefix) + strlen(name) + 3 > MAX_DNS_NAMELEN )
13614             return 0;
13615
13616         /* Realm names don't (normally) end with ".", but if the query
13617            doesn't end with "." and doesn't get an answer as is, the
13618            resolv code will try appending the local domain.  Since the
13619            realm names are absolutes, let's stop that.
13620
13621            But only if a name has been specified.  If we are performing
13622            a search on the prefix alone then the intention is to allow
13623            the local domain or domain search lists to be expanded.
13624         */
13625         h = host + strlen (host);
13626         ckmakmsg(host,sizeof(host),prefix, ".", name,
13627                  ((h > host) && (h[-1] != '.'))?".":NULL);
13628
13629     }
13630     size = res_search(host, C_IN, T_TXT, answer.bytes, sizeof(answer.bytes));
13631
13632     if (size < 0)
13633         return 0;
13634
13635     p = answer.bytes;
13636
13637     numqueries = ntohs(answer.hdr.qdcount);
13638     numanswers = ntohs(answer.hdr.ancount);
13639
13640     p += sizeof(HEADER);
13641
13642     /*
13643      * We need to skip over the questions before we can get to the answers,
13644      * which means we have to iterate over every query record.  We use
13645      * dn_expand to tell us how long each compressed name is.
13646      */
13647
13648     while (numqueries--) {
13649         len = dn_expand(answer.bytes, answer.bytes + size, p, host,
13650                          sizeof(host));
13651         if (len < 0)
13652             return 0;
13653         INCR_CHECK(p, len + 4);         /* Name plus type plus class */
13654     }
13655
13656     /*
13657      * We're now pointing at the answer records.  Process the first
13658      * TXT record we find.
13659      */
13660
13661     while (numanswers--) {
13662
13663         /* First the name; use dn_expand to get the compressed size */
13664         len = dn_expand(answer.bytes, answer.bytes + size, p,
13665                         host, sizeof(host));
13666         if (len < 0)
13667             return 0;
13668         INCR_CHECK(p, len);
13669
13670         /* Next is the query type */
13671         CHECK(p, 2);
13672         type = NTOHSP(p,2);
13673
13674         /* Next is the query class; also skip over 4 byte TTL */
13675         CHECK(p,6);
13676         class = NTOHSP(p,6);
13677
13678         /* Record data length - make sure we aren't truncated */
13679
13680         CHECK(p,2);
13681         rdlen = NTOHSP(p,2);
13682
13683         if (p + rdlen > answer.bytes + size)
13684             return 0;
13685
13686         /*
13687          * If this is a TXT record, return the string.  Note that the
13688          * string has a 1-byte length in the front
13689          */
13690         /* XXX What about flagging multiple TXT records as an error?  */
13691
13692         if (class == C_IN && type == T_TXT) {
13693             len = *p++;
13694             if (p + len > answer.bytes + size)
13695                 return 0;
13696             *retstr = malloc(len + 1);
13697             if (*retstr == NULL)
13698                 return ENOMEM;
13699             strncpy(*retstr, (char *) p, len);
13700             (*retstr)[len] = '\0';
13701             /* Avoid a common error. */
13702             if ( (*retstr)[len-1] == '.' )
13703                 (*retstr)[len-1] = '\0';
13704             return 1;
13705         }
13706     }
13707
13708     return 0;
13709 }
13710 #undef INCR_CHECK
13711 #undef CHECK
13712 #undef NTOHSP
13713 #endif /* CK_DNS_SRV */
13714
13715 #ifdef TNCODE
13716 #ifdef CK_FORWARD_X
13717 #ifdef UNIX
13718 #include <sys/un.h>
13719 #define FWDX_UNIX_SOCK
13720 #ifndef AF_LOCAL
13721 #define AF_LOCAL AF_UNIX
13722 #endif
13723 #ifndef PF_LOCAL
13724 #define PF_LOCAL PF_UNIX
13725 #endif
13726 #ifndef SUN_LEN
13727 /* Evaluate to actual length of the `sockaddr_un' structure.  */
13728 #define SUN_LEN(ptr) ((size_t) (((struct sockaddr_un *) 0)->sun_path)         \
13729                       + strlen ((ptr)->sun_path))
13730 #endif
13731 #endif /* UNIX */
13732 int
13733 fwdx_create_listen_socket(screen) int screen; {
13734 #ifdef NOPUTENV
13735     return(-1);
13736 #else /* NOPUTENV */
13737     struct sockaddr_in saddr;
13738     int display, port, sock=-1, i;
13739     static char env[512];
13740
13741     /*
13742      * X Windows Servers support multiple displays by listening on
13743      * one socket per display.  Display 0 is port 6000; Display 1 is
13744      * port 6001; etc.
13745      *
13746      * We start by trying to open port 6001 so that display 0 is
13747      * reserved for the local X Windows Server.
13748      */
13749
13750     for ( display=1; display < 1000 ; display++  ) {
13751
13752         if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
13753             debug(F111,"fwdx_create_listen_socket()","socket() < 0",sock);
13754             return(-1);
13755         }
13756
13757         port = 6000 + display;
13758         bzero((char *)&saddr, sizeof(saddr));
13759         saddr.sin_family = AF_INET;
13760         saddr.sin_addr.s_addr = inet_addr(myipaddr);
13761         saddr.sin_port = htons(port);
13762
13763         if (bind(sock, (struct sockaddr *)&saddr, sizeof(saddr)) < 0) {
13764             i = errno;                  /* Save error code */
13765 #ifdef TCPIPLIB
13766             socket_close(sock);
13767 #else /* TCPIPLIB */
13768             close(sock);
13769 #endif /* TCPIPLIB */
13770             sock = -1;
13771             debug(F110,"fwdx_create_listen_socket()","bind() < 0",0);
13772             continue;
13773         }
13774
13775         debug(F100,"fdwx_create_listen_socket() bind OK","",0);
13776         break;
13777     }
13778
13779     if ( display > 1000 ) {
13780         debug(F100,"fwdx_create_listen_socket() Out of Displays","",0);
13781         return(-1);
13782     }
13783
13784     if (listen(sock, 5) < 0) {
13785         i = errno;                  /* Save error code */
13786 #ifdef TCPIPLIB
13787         socket_close(sock);
13788 #else /* TCPIPLIB */
13789         close(sock);
13790 #endif /* TCPIPLIB */
13791         debug(F101,"fdwx_create_listen_socket() listen() errno","",errno);
13792         return(-1);
13793     }
13794     debug(F100,"fwdx_create_listen_socket() listen OK","",0);
13795
13796     TELOPT_SB(TELOPT_FORWARD_X).forward_x.listen_socket = sock;
13797     if (!myipaddr[0])
13798         getlocalipaddr();
13799     if ( myipaddr[0] )
13800         ckmakxmsg(env,sizeof(env),"DISPLAY=",myipaddr,":",
13801                   ckuitoa(display),":",ckuitoa(screen),
13802                   NULL,NULL,NULL,NULL,NULL,NULL);
13803     else
13804         ckmakmsg(env,sizeof(env),"DISPLAY=",ckuitoa(display),":",
13805                  ckuitoa(screen));
13806     putenv(env);
13807     return(0);
13808 #endif /* NOPUTENV */
13809 }
13810
13811
13812 int
13813 fwdx_open_client_channel(channel) int channel; {
13814     char * env;
13815     struct sockaddr_in saddr;
13816 #ifdef FWDX_UNIX_SOCK
13817     struct sockaddr_un saddr_un = { AF_LOCAL };
13818 #endif /* FWDX_UNIX_SOCK */
13819     int colon, dot, display, port, sock, i, screen;
13820     int family;
13821     char buf[256], * host=NULL, * rest=NULL;
13822 #ifdef TCP_NODELAY
13823     int on=1;
13824 #endif /* TCP_NODELAY */
13825
13826     debug(F111,"fwdx_create_client_channel()","channel",channel);
13827
13828     for ( i=0; i<MAXFWDX ; i++ ) {
13829         if (TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[i].id == channel) {
13830             /* Already open */
13831             debug(F110,"fwdx_create_client_channel()","already open",0);
13832             return(0);
13833         }
13834     }
13835
13836     env = getenv("DISPLAY");
13837     if ( !env )
13838       env = (char *)tn_get_display();
13839     if ( env )
13840       ckstrncpy(buf,env,256);
13841     else
13842       ckstrncpy(buf,"127.0.0.1:0.0",256);
13843
13844     bzero((char *)&saddr,sizeof(saddr));
13845     saddr.sin_family = AF_INET;
13846
13847     if (!fwdx_parse_displayname(buf,
13848                                 &family,
13849                                 &host,
13850                                 &display,
13851                                 &screen,
13852                                 &rest
13853                                 )
13854         ) {
13855         if ( host ) free(host);
13856         if ( rest ) free(rest);
13857         return(0);
13858     }
13859     if (rest) free(rest);
13860
13861 #ifndef FWDX_UNIX_SOCK
13862   /* if $DISPLAY indicates use of unix domain sockets, but we don't support it,
13863    * we change things to use inet sockets on the ip loopback interface instead,
13864    * and hope that it works.
13865    */
13866     if (family == FamilyLocal) {
13867         debug(F100,"fwdx_create_client_channel() FamilyLocal","",0);
13868         family = FamilyInternet;
13869         if (host) free(host);
13870         if (host = malloc(strlen("localhost") + 1))
13871             strcpy(host, "localhost");
13872         else {
13873             return(-1);
13874         }
13875     }
13876 #else /* FWDX_UNIX_SOCK */
13877     if (family == FamilyLocal) {
13878         if (host) free(host);
13879         sock = socket(PF_LOCAL, SOCK_STREAM, 0);
13880         if (sock < 0)
13881             return(-1);
13882
13883         ckmakmsg(buf,sizeof(buf),"/tmp/.X11-unix/X",ckitoa(display),NULL,NULL);
13884         strncpy(saddr_un.sun_path, buf, sizeof(saddr_un.sun_path));
13885         if (connect(sock,(struct sockaddr *)&saddr_un, SUN_LEN(&saddr_un)) < 0)
13886           return(-1);
13887     } else
13888 #endif  /* FWDX_UNIX_SOCK */
13889     {
13890         /* Otherwise, we are assuming FamilyInternet */
13891         if (host) {
13892             ckstrncpy(buf,host,sizeof(buf));
13893             free(host);
13894         } else
13895             ckstrncpy(buf,myipaddr,sizeof(buf));
13896
13897         debug(F111,"fwdx_create_client_channel()","display",display);
13898
13899         port = 6000 + display;
13900         saddr.sin_port = htons(port);
13901
13902         debug(F110,"fwdx_create_client_channel() ip-address",buf,0);
13903         saddr.sin_addr.s_addr = inet_addr(buf);
13904         if ( saddr.sin_addr.s_addr == (unsigned long) -1
13905 #ifdef INADDR_NONE
13906              || saddr.sin_addr.s_addr == INADDR_NONE
13907 #endif /* INADDR_NONE */
13908              )
13909         {
13910             struct hostent *host;
13911             host = gethostbyname(buf);
13912             if ( host == NULL )
13913                 return(-1);
13914             host = ck_copyhostent(host);
13915 #ifdef HADDRLIST
13916 #ifdef h_addr
13917             /* This is for trying multiple IP addresses - see <netdb.h> */
13918             if (!(host->h_addr_list))
13919                 return(-1);
13920             bcopy(host->h_addr_list[0],
13921                    (caddr_t)&saddr.sin_addr,
13922                    host->h_length
13923                    );
13924 #else
13925             bcopy(host->h_addr, (caddr_t)&saddr.sin_addr, host->h_length);
13926 #endif /* h_addr */
13927 #else  /* HADDRLIST */
13928             bcopy(host->h_addr, (caddr_t)&saddr.sin_addr, host->h_length);
13929 #endif /* HADDRLIST */
13930         }
13931
13932         if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
13933             debug(F111,"fwdx_create_client_channel()","socket() < 0",sock);
13934             return(-1);
13935         }
13936
13937         if ( connect(sock, (struct sockaddr *)&saddr, sizeof(saddr)) < 0) {
13938             debug(F110,"fwdx_create_client_channel()","connect() failed",0);
13939 #ifdef TCPIPLIB
13940             socket_close(sock);
13941 #else /* TCPIPLIB */
13942             close(sock);
13943 #endif /* TCPIPLIB */
13944             return(-1);
13945         }
13946
13947 #ifdef TCP_NODELAY
13948         setsockopt(sock,IPPROTO_TCP,TCP_NODELAY,(char *)&on,sizeof(on));
13949 #endif /* TCP_NODELAY */
13950     }
13951
13952     for (i = 0; i < MAXFWDX; i++) {
13953      if (TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[i].id == -1) {
13954          TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[i].fd = sock;
13955          TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[i].id = channel;
13956        TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[i].need_to_send_xauth = 1;
13957          debug(F111,"fwdx_create_client_channel()","socket",sock);
13958          return(0);
13959      }
13960     }
13961     return(-1);
13962 }
13963
13964 int
13965 fwdx_server_avail() {
13966     char * env;
13967     struct sockaddr_in saddr;
13968 #ifdef FWDX_UNIX_SOCK
13969     struct sockaddr_un saddr_un = { AF_LOCAL };
13970 #endif  /* FWDX_UNIX_SOCK */
13971     int colon, dot, display, port, sock, i, screen;
13972     char buf[256], *host=NULL, *rest=NULL;
13973 #ifdef TCP_NODELAY
13974     int on=1;
13975 #endif /* TCP_NODELAY */
13976     int family;
13977
13978     env = getenv("DISPLAY");
13979     if ( !env )
13980       env = (char *)tn_get_display();
13981     if ( env )
13982       ckstrncpy(buf,env,256);
13983     else
13984       ckstrncpy(buf,"127.0.0.1:0.0",256);
13985
13986     bzero((char *)&saddr,sizeof(saddr));
13987     saddr.sin_family = AF_INET;
13988
13989     if (!fwdx_parse_displayname(buf,&family,&host,&display,&screen,&rest)) {
13990         if ( host ) free(host);
13991         if ( rest ) free(rest);
13992         return(0);
13993     }
13994     if (rest) free(rest);
13995
13996 #ifndef FWDX_UNIX_SOCK
13997   /* if $DISPLAY indicates use of unix domain sockets, but we don't support it,
13998    * we change things to use inet sockets on the ip loopback interface instead,
13999    * and hope that it works.
14000    */
14001     if (family == FamilyLocal) {
14002         family = FamilyInternet;
14003         if (host) free(host);
14004         if (host = malloc(strlen("localhost") + 1))
14005             strcpy(host, "localhost");
14006         else {
14007             return(-1);
14008         }
14009     }
14010 #else /* FWDX_UNIX_SOCK */
14011     if (family == FamilyLocal) {
14012         debug(F100,"fwdx_server_avail() FamilyLocal","",0);
14013         if (host) free(host);
14014         sock = socket(PF_LOCAL, SOCK_STREAM, 0);
14015         if (sock < 0)
14016             return(0);
14017
14018         ckmakmsg(buf,sizeof(buf),"/tmp/.X11-unix/X",ckitoa(display),NULL,NULL);
14019         strncpy(saddr_un.sun_path, buf, sizeof(saddr_un.sun_path));
14020         if (connect(sock,(struct sockaddr *)&saddr_un,SUN_LEN(&saddr_un)) < 0)
14021             return(0);
14022         close(sock);
14023         return(1);
14024     }
14025 #endif  /* FWDX_UNIX_SOCK */
14026
14027     /* Otherwise, we are assuming FamilyInternet */
14028     if (host) {
14029         ckstrncpy(buf,host,sizeof(buf));
14030         free(host);
14031     } else
14032         ckstrncpy(buf,myipaddr,sizeof(buf));
14033
14034     debug(F111,"fwdx_server_avail()","display",display);
14035
14036     port = 6000 + display;
14037     saddr.sin_port = htons(port);
14038
14039     debug(F110,"fwdx_server_avail() ip-address",buf,0);
14040     saddr.sin_addr.s_addr = inet_addr(buf);
14041     if ( saddr.sin_addr.s_addr == (unsigned long) -1
14042 #ifdef INADDR_NONE
14043          || saddr.sin_addr.s_addr == INADDR_NONE
14044 #endif /* INADDR_NONE */
14045          )
14046     {
14047         struct hostent *host;
14048         host = gethostbyname(buf);
14049         if ( host == NULL ) {
14050             debug(F110,"fwdx_server_avail() gethostbyname() failed",
14051                    myipaddr,0);
14052             return(-1);
14053         }
14054         host = ck_copyhostent(host);
14055 #ifdef HADDRLIST
14056 #ifdef h_addr
14057         /* This is for trying multiple IP addresses - see <netdb.h> */
14058         if (!(host->h_addr_list))
14059             return(-1);
14060         bcopy(host->h_addr_list[0],
14061                (caddr_t)&saddr.sin_addr,
14062                host->h_length
14063                );
14064 #else
14065         bcopy(host->h_addr, (caddr_t)&saddr.sin_addr, host->h_length);
14066 #endif /* h_addr */
14067 #else  /* HADDRLIST */
14068         bcopy(host->h_addr, (caddr_t)&saddr.sin_addr, host->h_length);
14069 #endif /* HADDRLIST */
14070     }
14071
14072     if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
14073         debug(F111,"fwdx_server_avail()","socket() < 0",sock);
14074         return(0);
14075     }
14076
14077     if ( connect(sock, (struct sockaddr *)&saddr, sizeof(saddr)) < 0) {
14078         debug(F110,"fwdx_server_avail()","connect() failed",0);
14079 #ifdef TCPIPLIB
14080         socket_close(sock);
14081 #else /* TCPIPLIB */
14082         close(sock);
14083 #endif /* TCPIPLIB */
14084         return(0);
14085     }
14086
14087 #ifdef TCPIPLIB
14088     socket_close(sock);
14089 #else /* TCPIPLIB */
14090     close(sock);
14091 #endif /* TCPIPLIB */
14092     return(1);
14093 }
14094
14095 int
14096 fwdx_open_server_channel() {
14097     int sock, ready_to_accept, sock2,channel,i;
14098 #ifdef TCP_NODELAY
14099     int on=1;
14100 #endif /* TCP_NODELAY */
14101 #ifdef UCX50
14102     static u_int saddrlen;
14103 #else
14104     static SOCKOPT_T saddrlen;
14105 #endif /* UCX50 */
14106     struct sockaddr_in saddr;
14107     char sb[8];
14108     extern char tn_msg[];
14109 #ifdef BSDSELECT
14110     fd_set rfds;
14111     struct timeval tv;
14112 #else
14113 #ifdef BELLSELCT
14114     fd_set rfds;
14115 #else
14116     fd_set rfds;
14117     struct timeval {
14118         long tv_sec;
14119         long tv_usec;
14120     } tv;
14121 #endif /* BELLSELECT */
14122 #endif /* BSDSELECT */
14123     unsigned short nchannel;
14124     unsigned char * p;
14125
14126     sock = TELOPT_SB(TELOPT_FORWARD_X).forward_x.listen_socket;
14127
14128   try_again:
14129
14130 #ifdef BSDSELECT
14131     tv.tv_sec  = tv.tv_usec = 0L;
14132     tv.tv_usec = 50;
14133     FD_ZERO(&rfds);
14134     FD_SET(sock, &rfds);
14135     ready_to_accept =
14136         ((select(FD_SETSIZE,
14137 #ifdef HPUX
14138 #ifdef HPUX1010
14139                   (fd_set *)
14140 #else
14141
14142                   (int *)
14143 #endif /* HPUX1010 */
14144 #else
14145 #ifdef __DECC
14146                   (fd_set *)
14147 #endif /* __DECC */
14148 #endif /* HPUX */
14149                   &rfds, NULL, NULL, &tv) > 0) &&
14150           FD_ISSET(sock, &rfds));
14151 #else /* BSDSELECT */
14152 #ifdef IBMSELECT
14153     ready_to_accept = (select(&sock, 1, 0, 0, 50) == 1);
14154 #else
14155 #ifdef BELLSELECT
14156     FD_ZERO(rfds);
14157     FD_SET(sock, rfds);
14158     ready_to_accept =
14159         ((select(128, rfds, NULL, NULL, 50) > 0) &&
14160           FD_ISSET(sock, rfds));
14161 #else
14162 /* Try this - what's the worst that can happen... */
14163
14164     tv.tv_sec  = tv.tv_usec = 0L;
14165     tv.tv_usec = 50;
14166     FD_ZERO(&rfds);
14167     FD_SET(sock, &rfds);
14168     ready_to_accept =
14169         ((select(FD_SETSIZE,
14170                   (fd_set *) &rfds, NULL, NULL, &tv) > 0) &&
14171           FD_ISSET(sock, &rfds));
14172 #endif /* BELLSELECT */
14173 #endif /* IBMSELECT */
14174 #endif /* BSDSELECT */
14175
14176     if ( !ready_to_accept )
14177         return(0);
14178
14179     if ((sock2 = accept(sock,(struct sockaddr *)&saddr,&saddrlen)) < 0) {
14180         int i = errno;                  /* save error code */
14181         debug(F101,"tcpsrv_open accept errno","",i);
14182         return(-1);
14183     }
14184
14185     /*
14186      * Now we have the open socket.  We must now find a channel to store
14187      * it in, and then notify the client.
14188      */
14189
14190     for ( channel=0;channel<MAXFWDX;channel++ ) {
14191         if ( TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[channel].fd == -1 )
14192             break;
14193     }
14194
14195     if ( channel == MAXFWDX ) {
14196 #ifdef TCPIPLIB
14197         socket_close(sock2);
14198 #else /* TCPIPLIB */
14199         close(sock2);
14200 #endif /* TCPIPLIB */
14201         return(-1);
14202     }
14203
14204     if ( fwdx_send_open(channel) < 0 ) {
14205 #ifdef TCPIPLIB
14206         socket_close(sock2);
14207 #else /* TCPIPLIB */
14208         close(sock2);
14209 #endif /* TCPIPLIB */
14210     }
14211
14212 #ifdef TCP_NODELAY
14213     setsockopt(sock2,IPPROTO_TCP,TCP_NODELAY,(char *)&on,sizeof(on));
14214 #endif /* TCP_NODELAY */
14215
14216     TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[channel].fd = sock2;
14217     TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[channel].id = channel;
14218     goto try_again;
14219
14220     return(0);  /* never reached */
14221 }
14222
14223 int
14224 fwdx_close_channel(channel) int channel; {
14225     int i,fd;
14226
14227     for ( i=0; i<MAXFWDX ; i++ ) {
14228         if (TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[i].id == channel)
14229             break;
14230     }
14231     if ( i == MAXFWDX )
14232         return(-1);
14233
14234     fd = TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[i].fd;
14235     TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[i].fd = -1;
14236     TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[i].id = -1;
14237     TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[i].need_to_send_xauth = 0;
14238
14239 #ifdef TCPIPLIB
14240     socket_close(fd);
14241 #else /* TCPIPLIB */
14242     close(fd);
14243 #endif /* TCPIPLIB */
14244     return(0);
14245 }
14246
14247 int
14248 fwdx_close_all() {
14249     int x,fd;
14250
14251     debug(F111,"fwdx_close_all()",
14252           "TELOPT_SB(TELOPT_FORWARD_X).forward_x.listen_socket",
14253           TELOPT_SB(TELOPT_FORWARD_X).forward_x.listen_socket);
14254
14255     if ( TELOPT_SB(TELOPT_FORWARD_X).forward_x.listen_socket != -1 ) {
14256 #ifdef TCPIPLIB
14257         socket_close(TELOPT_SB(TELOPT_FORWARD_X).forward_x.listen_socket);
14258 #else /* TCPIPLIB */
14259         close(TELOPT_SB(TELOPT_FORWARD_X).forward_x.listen_socket);
14260 #endif /* TCPIPLIB */
14261         TELOPT_SB(TELOPT_FORWARD_X).forward_x.listen_socket = -1;
14262     }
14263
14264     for (x = 0; x < MAXFWDX; x++) {
14265      if (TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].fd != -1) {
14266       fd = TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].fd;
14267       TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].fd = -1;
14268       TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].id = -1;
14269       TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].need_to_send_xauth = 0;
14270       TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].suspend = 0;
14271 #ifdef TCPIPLIB
14272       socket_close(fd);
14273 #else /* TCPIPLIB */
14274       close(fd);
14275 #endif /* TCPIPLIB */
14276      }
14277     }
14278     return(0);
14279 }
14280
14281 /* The following definitions are for Unix */
14282 #ifndef socket_write
14283 #define socket_write(f,s,n)    write(f,s,n)
14284 #endif /* socket_write */
14285 #ifndef socket_read
14286 #define socket_read(f,s,n)     read(f,s,n)
14287 #endif /* socket_read */
14288
14289 int
14290 fwdx_write_data_to_channel(channel, data, len)
14291     int channel; char * data; int len;
14292 {
14293     int sock, count, try=0, length = len, i;
14294
14295     if ( len <= 0 )
14296         return(0);
14297
14298     for ( i=0; i<MAXFWDX ; i++ ) {
14299         if (TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[i].id == channel)
14300             break;
14301     }
14302     if ( i == MAXFWDX ) {
14303         debug(F110,"fwdx_write_data_to_channel",
14304                "attempting to write to closed channel",0);
14305         return(-1);
14306     }
14307
14308     sock = TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[i].fd;
14309     debug(F111,"fwdx_write_data_to_channel","socket",sock);
14310     ckhexdump("fwdx_write_data_to_channel",data,len);
14311
14312   fwdx_write_data_to_channel_retry:
14313
14314     if ((count = socket_write(sock,data,len)) < 0) {
14315         int s_errno = socket_errno; /* maybe a function */
14316         debug(F101,"fwdx_write_data_to_channel socket_write error","",s_errno);
14317 #ifdef BETATEST
14318         printf("fwdx_write_data_to_channel error\r\n");
14319 #endif /* BETATEST */
14320 #ifdef OS2
14321         if (os2socketerror(s_errno) < 0)
14322             return(-2);
14323 #endif /* OS2 */
14324         return(-1);                 /* Call it an i/o error */
14325     }
14326     if (count < len) {
14327         debug(F111,"fwdx_write_data_to_channel socket_write",data,count);
14328         if (count > 0) {
14329             data += count;
14330             len -= count;
14331         }
14332         debug(F111,"fwdx_write_data_to_channel retry",data,len);
14333         if ( len > 0 )
14334             goto fwdx_write_data_to_channel_retry;
14335     }
14336
14337     debug(F111,"fwdx_write_data_to_channel complete",data,length);
14338     return(length); /* success - return total length */
14339 }
14340
14341 VOID
14342 fwdx_check_sockets(fd_set *ibits)
14343 {
14344     int x, sock, channel, bytes;
14345     static char buffer[32000];
14346
14347     debug(F100,"fwdx_check_sockets()","",0);
14348     if ( sstelnet && !TELOPT_ME(TELOPT_FORWARD_X) ||
14349          !sstelnet && !TELOPT_U(TELOPT_FORWARD_X)) {
14350         debug(F110,"fwdx_check_sockets()","TELOPT_FORWARD_X not negotiated",0);
14351         return;
14352     }
14353
14354     for (x = 0; x < MAXFWDX; x++) {
14355         if ( TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].fd == -1 ||
14356              TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].suspend )
14357             continue;
14358
14359         sock = TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].fd;
14360         if (FD_ISSET(sock, ibits))
14361         {
14362             channel = TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].id;
14363             debug(F111,"fwdx_check_sockets()","channel set",channel);
14364
14365             bytes = socket_read(sock, buffer, sizeof(buffer));
14366             if (bytes > 0)
14367                 fwdx_send_data_from_channel(channel, buffer, bytes);
14368             else if (bytes == 0) {
14369                 fwdx_close_channel(channel);
14370                 fwdx_send_close(channel);
14371             }
14372         }
14373     }
14374 }
14375
14376 int
14377 fwdx_init_fd_set(fd_set *ibits)
14378 {
14379     int x,set=0,cnt=0;
14380
14381     if ( sstelnet && !TELOPT_ME(TELOPT_FORWARD_X) ||
14382          !sstelnet && !TELOPT_U(TELOPT_FORWARD_X)) {
14383         debug(F110,"fwdx_init_fd_set()","TELOPT_FORWARD_X not negotiated",0);
14384         return(0);
14385     }
14386
14387     if (TELOPT_SB(TELOPT_FORWARD_X).forward_x.listen_socket != -1) {
14388         set++;
14389         FD_SET(TELOPT_SB(TELOPT_FORWARD_X).forward_x.listen_socket, ibits);
14390     }
14391     for (x = 0; x < MAXFWDX; x++) {
14392         if (TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].fd != -1) {
14393             cnt++;
14394             if (TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].suspend)
14395                 continue;
14396             set++;
14397             FD_SET(TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].fd, ibits);
14398         }
14399     }
14400     if (set + cnt == 0) {
14401         return(-1);
14402     } else {
14403         return(set);
14404     }
14405 }
14406
14407 #ifdef NT
14408 VOID
14409 fwdx_thread( VOID * dummy )
14410 {
14411     fd_set ifds;
14412     struct timeval tv;
14413     extern int priority;
14414     int n;
14415
14416     setint();
14417     SetThreadPrty(priority,isWin95() ? 3 : 11);
14418
14419     while ( !sstelnet && TELOPT_U(TELOPT_FORWARD_X) ||
14420             sstelnet && TELOPT_ME(TELOPT_FORWARD_X))
14421     {
14422         FD_ZERO(&ifds);
14423         n = fwdx_init_fd_set(&ifds);
14424         if (n > 0) {
14425             tv.tv_sec = 0;
14426             tv.tv_usec = 2500;
14427             if ( select(FD_SETSIZE, &ifds, NULL, NULL, &tv) > 0 )
14428                 fwdx_check_sockets(&ifds);
14429
14430         } else if (n < 0) {
14431             TELOPT_SB(TELOPT_FORWARD_X).forward_x.thread_started = 0;
14432             ckThreadEnd(NULL);
14433         } else {
14434             sleep(1);
14435         }
14436     }
14437 }
14438 #endif /* NT */
14439 #endif /* CK_FORWARD_X */
14440 #endif /* TNCODE */
14441 #endif /* NETCONN */