1 char *cknetv = "Network support, 9.0.297, 14 Jul 2011";
2
3 /* C K C N E T -- Network support */
4
5 /*
6 Copyright (C) 1985, 2011,
7 Trustees of Columbia University in the City of New York.
8 All rights reserved. See the C-Kermit COPYING.TXT file or the
9 copyright text in the ckcmai.c module for disclaimer and permissions.
10 */
11
12 /*
13 REMINDER: Any changes made to this file that other modules depend must
14 also be made to cklnet.c (for VOS) until such time as cklnet.c and this
15 module are merged back together.
16
17 NOTE TO CONTRIBUTORS: This file, and all the other shared (ckc and cku)
18 C-Kermit source files, must be compatible with C preprocessors that support
19 only #ifdef, #else, #endif, #define, and #undef. Please do not use #if,
20 logical operators, or other preprocessor features in this module. Also,
21 don't use any ANSI C constructs except within #ifdef CK_ANSIC..#endif.
22
23 Authors:
24
25 Frank da Cruz (fdc@columbia.edu),
26 Columbia University Academic Information Systems, New York City.
27 Jeffrey E Altman (jaltman@secure-endpoints.com) -- Primary
28 maintainer/developer since about 1996.
29 netopen() routine for TCP/IP originally by Ken Yap, Rochester University
30 (ken@cs.rochester.edu) (no longer at that address).
31 Missing pieces for Excelan sockets library from William Bader.
32 Telnet protocol by Frank da Cruz and Jeffrey Altman.
33 Rlogin protocol by Jeffrey E Altman.
34 SSL support adapted by Jeffrey E Altman from work done by
35 Tim Hudson <tjh@cryptosoft.com> +61 7 32781581
36 TLS support by Jeffrey E Altman.
37 HTTP support by Jeffrey E Altman.
38 TGV MultiNet code by Frank da Cruz.
39 MultiNet code adapted to WIN/TCP by Ray Hunter of TWG.
40 MultiNet code adapted to DEC TCP/IP by Lee Tibbert of DEC and Frank da Cruz.
41 TCP/IP support adapted to IBM TCP/IP 1.2.1,2.0 for OS/2 by Kai Uwe Rommel.
42 CMU-OpenVMS/IP modifications by Mike O'Malley, Digital (DEC).
43 X.25 support by Marcello Frutig, Catholic University,
44 Rio de Janeiro, Brazil (frutig@rnp.impa.br) with fixes from
45 Stefaan Eeckels, Eurokom, Luxembourg.
46 David Lane added support for Stratus VOS X.25 1996.
47 Stephen Riehm added support for IBM AIX X.25 in April 1998.
48 Other contributions as indicated in the code.
49 */
50 #define CKCNET_C
51 #include "ckcsym.h"
52 #include "ckcdeb.h"
53 #include "ckcker.h"
54 #include "ckcasc.h"
55 #ifdef I386IX /* Has to come before ckcnet.h in */
56 #include <errno.h> /* this version, but after in others */
57 #endif /* I386IX */
58 #include "ckcnet.h" /* which includes ckctel.h */
59 #ifdef CK_SSL
60 #include "ck_ssl.h"
61 #endif /* CK_SSL */
62
63 #ifdef CK_DNS_SRV
64 #ifdef OS2
65 #ifdef NT
66 #include <wshelper.h>
67 #else /* NT */
68 /* !Error OS/2 does not support DNS Service Records. */
69 #endif /* NT */
70 #else /* OS2 */
71 #include <arpa/inet.h>
72 #ifdef USE_NAMESER_COMPAT
73 #include <arpa/nameser_compat.h>
74 #endif /* USE_NAMESER_COMPAT */
75
76 #ifdef MINIX3
77 #include <net/gen/resolv.h>
78 #include <net/gen/nameser.h>
79 #else
80 #include <arpa/nameser.h>
81 #include <resolv.h>
82 #endif /* MINIX 3 */
83
84 #ifndef PS2AIX10
85 #ifndef BSD4
86 #ifndef I386IX
87 #ifndef RTAIX
88 #include <netdb.h>
89 #endif /* RTAIX */
90 #endif /* I386IX */
91 #endif /* BSD4 */
92 #endif /* PS2AIX10 */
93 #endif /* OS2 */
94 #ifndef T_SRV
95 #define T_SRV 33
96 #endif /* T_SRV */
97 #ifndef T_TXT
98 #define T_TXT 16
99 #endif /* T_TXT */
100
101 /* for old Unixes and friends ... */
102 #ifndef MAXHOSTNAMELEN
103 #define MAXHOSTNAMELEN 64
104 #endif /* MAXHOSTNAMELEN */
105
106 #define MAX_DNS_NAMELEN (15*(MAXHOSTNAMELEN + 1)+1)
107 #endif /* CK_DNS_SRV */
108
109 #ifdef NONET
110 #ifdef TCPIPLIB
111 #undef TCPIPLIB
112 #endif /* TCPIPLIB */
113 #endif /* NONET */
114
115 #ifndef NOMHHOST
116 #ifdef datageneral
117 #define NOMHHOST
118 #else
119 #ifdef HPUX5WINTCP
120 #define NOMHHOST
121 #endif /* HPUX5WINTCP */
122 #endif /* datageneral */
123 #endif /* NOMHHOST */
124
125 #ifdef INADDRX
126 struct in_addr inaddrx;
127 #endif /* INADDRX */
128
129 int ttnet = NET_NONE; /* Network type */
130 int ttnproto = NP_DEFAULT; /* Network virtual terminal protocol */
131
132 /* 0 = don't lowercase username for Rlogin/Telnet protocol */
133 /* nonzero = do lowercase it. Add a SET command if necessary... */
134 #ifdef VMS
135 int ck_lcname = 1;
136 #else
137 int ck_lcname = 0;
138 #endif /* VMS */
139
140 extern int /* External variables */
141 duplex, debses, seslog, sessft, wasclosed,
142 ttyfd, quiet, msgflg, what, nettype, ttmdm;
143 #ifdef IKSD
144 extern int inserver;
145 #endif /* IKSD */
146
147 char myipaddr[20] = { '\0' }; /* Global copy of my IP address */
148 char hostipaddr[64] = { '\0' }; /* Global copy of remote IP address */
149
150 #ifdef NETCONN
151 /* Don't need any of this if there is no network support. */
152
153 #ifndef OS2
154 /* Current fd-swapping hack is not thread-safe */
155 #define HTTP_BUFFERING
156 #endif /* OS2 */
157
158 #ifdef HTTP_BUFFERING
159 #define HTTP_INBUFLEN 8192
160 static char http_inbuf[HTTP_INBUFLEN];
161 static int http_bufp = 0, http_count;
162 #endif /* HTTP_BUFFERING */
163
164 /*
165 NETLEBUF is (must be) defined for those platforms that call this
166 module to do network i/o (e.g. netinc(), nettchk(), etc) rather
167 than doing it themselves (ttinc(), ttchk(), etc). In this case
168 the Telnet local-echo buffers and routines are defined and referenced
169 here, rather than in the ck?tio.c module.
170 */
171 #ifdef NETLEBUF
172 #define LEBUFSIZ 4096
173 int ttpush = -1, le_data = 0; /* These are seen from outside */
174 static CHAR le_buf[LEBUFSIZ]; /* These are used internally */
175 static int le_start = 0, le_end = 0;
176 int tt_push_inited = 0;
177 #endif /* NETLEBUF */
178
179 #ifdef CK_SOCKS /* SOCKS Internet relay package */
180 #ifdef CK_SOCKS5 /* SOCKS 5 */
181 #define accept SOCKSaccept
182 #define bind SOCKSbind
183 #define connect SOCKSconnect
184 #define getsockname SOCKSgetsockname
185 #define listen SOCKSlisten
186 #else /* Not SOCKS 5 */
187 #define accept Raccept
188 #define bind Rbind
189 #define connect Rconnect
190 #define getsockname Rgetsockname
191 #define listen Rlisten
192 #endif /* CK_SOCKS5 */
193 #endif /* CK_SOCKS */
194
195 #ifdef DEC_TCPIP
196 #include <time.h>
197 #include <inet.h>
198 #endif /* DEC_TCPIP */
199
200 /* Also see ckcnet.h -- hmmm, why don't we always include inet.h? */
201
202 #ifdef HPUX
203 #ifndef HPUX7 /* HPUX 7.00 doesn't have it */
204 #ifndef HPUX6 /* HPUX 6.00 doesn't have it */
205 #include <arpa/inet.h> /* For inet_ntoa() prototype */
206 #endif /* HPUX6 */
207 #endif /* HPUX7 */
208 #endif /* HPUX */
209
210 #ifdef CMU_TCPIP
211 #include <time.h>
212 #endif /* CMU_TCPIP */
213
214 #ifndef NODCLTIMEVAL
215 #ifdef DCLTIMEVAL /* UnixWare 7 */
216 struct timeval { /* And define these ourselves. */
217 long tv_sec; /* (see comments in ckutio.c) */
218 long tv_usec;
219 };
220 struct timezone {
221 int tz_minuteswest;
222 int tz_dsttime;
223 };
224 #endif /* DCLTIMEVAL */
225 #endif /* NODCLTIMEVAL */
226
227 #ifdef WINTCP
228
229 #include <setjmp.h>
230 #include <signal.h>
231 #include <sys/time.h>
232 /*
233 The WIN/TCP code path is the same as that for MultiNet.
234 Only the routine names have changed ...
235 */
236 #define socket_read netread
237 #define socket_ioctl ioctl
238 #define socket_write netwrite
239 #define socket_close netclose
240
241 #ifdef OLD_TWG /* some routines have evolved */
242 extern int vmserrno, uerrno;
243 #define socket_errno uerrno
244 #define socket_perror perror /* which uses errno, not uerrno! */
245 #else
246 #define socket_errno errno
247 #define socket_perror win$perror
248 #endif /* OLD_TWG */
249
250 #else /* Not WINTCP */
251
252 #ifdef OSF13
253 #ifdef CK_ANSIC
254 #ifdef _NO_PROTO
255 #undef _NO_PROTO
256 #endif /* _NO_PROTO */
257 #endif /* CK_ANSIC */
258 #endif /* OSF13 */
259
260 #ifndef I386IX
261 #ifndef HPUXPRE65
262 #include <errno.h> /* Error number symbols */
263 #else
264 #ifndef ERRNO_INCLUDED
265 #include <errno.h> /* Error number symbols */
266 #endif /* ERRNO_INCLUDED */
267 #endif /* HPUXPRE65 */
268 #endif /* I386IX */
269
270 #include <signal.h> /* Everybody needs this */
271
272 #ifdef ZILOG /* Zilog has different name for this */
273 #include <setret.h>
274 #else
275 #include <setjmp.h>
276 #endif /* ZILOG */
277
278 #endif /* WINTCP */
279
280 #ifdef datageneral /* Data General AOS/VS */
281 #include <:usr:include:vs_tcp_errno.h>
282 #include <:usr:include:sys:vs_tcp_types.h>
283 #ifdef SELECT
284 /*
285 NOTE: This can be compiled and linked OK with SELECT defined
286 but it doesn't work at all. Anybody who cares and knows how
287 to fix it, feel free.
288 */
289 #include <:usr:include:sys:vs_tcp_time.h>
290 #endif /* SELECT */
291 #include <:usr:include:sys:socket.h>
292 #include <:usr:include:netinet:in.h>
293 #include <:usr:include:netdb.h>
294 #endif /* datageneral */
295
296 #ifndef socket_errno
297 #define socket_errno errno
298 #endif /* socket_errno */
299
300 #ifdef TNCODE
301 extern int tn_deb;
302 #endif /* TNCODE */
303
304 int tcp_rdns = /* Reverse DNS lookup */
305 #ifdef DEC_TCPIP_OLD
306 SET_OFF /* Doesn't seem to work in UCX */
307 #else
308 SET_AUTO
309 #endif /* DEC_TCPIP */
310 ;
311 #ifdef CK_DNS_SRV
312 int tcp_dns_srv = SET_OFF;
313 #endif /* CK_DNS_SRV */
314
315 _PROTOTYP( char * cmcvtdate, (char *, int) );
316
317 #ifdef RLOGCODE
318 _PROTOTYP( int rlog_ctrl, (CHAR *, int) );
319 _PROTOTYP( static int rlog_oob, (CHAR *, int) );
320 #ifndef TCPIPLIB
321 _PROTOTYP( static SIGTYP rlogoobh, ( int ) );
322 #endif /* TCPIPLIB */
323 _PROTOTYP( static int rlog_ini, (CHAR *, int,
324 struct sockaddr_in *,
325 struct sockaddr_in *) );
326 int rlog_mode = RL_COOKED;
327 int rlog_stopped = 0;
328 int rlog_inband = 0;
329 #endif /* RLOGCODE */
330
331 #ifndef NOICP
332 extern int doconx; /* CONNECT-class command active */
333 #endif /* NOICP */
334
335 #ifdef IBMX25
336 /* This variable should probably be generalised for true client/server
337 * support - ie: the fd of the listening server, accepted calls should
338 * be forked or at least handled via a second fd (for IBM's X.25 -
339 * ttyfd always holds the active fd - ie the server becomes inactive
340 * as long as a client is connected, and becomes active again when the
341 * connection is closed)
342 */
343 int x25serverfd = 0; /* extern in ckcnet.h */
344 int x25seqno = 0; /* Connection sequence number */
345 int x25lastmsg = -1; /* A cheapskate's state table */
346
347 #define X25_CLOSED 0 /* Default state: no connection, no STREAM */
348 #define X25_SETUP 1 /* X.25 has been set up (no connection) */
349 #define X25_CONNECTED 2 /* X.25 connection has been established */
350 int x25_state = X25_CLOSED; /* Default state */
351 #endif /* IBMX25 */
352
353 #ifndef DEBUG
354 #define deblog 0
355 #endif /* DEBUG */
356
357 #ifdef CK_NAWS /* Negotiate About Window Size */
358 #ifdef RLOGCODE
359 _PROTOTYP( int rlog_naws, (void) );
360 #endif /* RLOGCODE */
361 #endif /* CK_NAWS */
362
363 #ifdef OS2 /* For terminal type name string */
364 #include "ckuusr.h"
365 #ifndef NT
366 #include <os2.h>
367 #undef COMMENT
368 #endif /* NT */
369 #include "ckocon.h"
370 extern int tt_type, max_tt;
371 extern struct tt_info_rec tt_info[];
372 extern char ttname[];
373 #else
374 #ifdef CK_AUTHENTICATION
375 #include "ckuusr.h"
376 #endif /* CK_AUTHENTICATION */
377 #endif /* OS2 */
378
379 #ifdef NT
380 extern int winsock_version;
381 #endif /* NT */
382
383 #ifdef CK_AUTHENTICATION
384 #include "ckuath.h"
385 #endif /* CK_AUTHENTICATION */
386
387 #include "ckcsig.h"
388
389 #ifndef OS2 /* For timeout longjumps */
390 static ckjmpbuf njbuf;
391 #endif /* OS2 */
392
393 #define NAMECPYL 1024 /* Local copy of hostname */
394 char namecopy[NAMECPYL]; /* Referenced by ckctel.c */
395 char namecopy2[NAMECPYL]; /* Referenced by ckctel.c */
396 #ifndef NOHTTP
397 char http_host_port[NAMECPYL]; /* orig host/port necessary for http */
398 char http_ip[20] = { '\0' }; /* ip address of host */
399 char http_port = 0;
400 int http_ssl = 0;
401 char * http_agent = 0;
402 int httpfd = -1; /* socket for http connections */
403 int http_code = 0;
404 #define HTTPBUFLEN 1024
405 char http_reply_str[HTTPBUFLEN] = "";
406 #endif /* NOHTTP */
407
408 char ipaddr[20] = { '\0' }; /* Global copy of IP address */
409 unsigned long myxipaddr = 0L; /* Ditto as a number */
410 #endif /* NETCONN */
411
412 char *tcp_address = NULL; /* Preferred IP Address */
413 extern char uidbuf[]; /* User ID buffer */
414 extern char pwbuf[]; /* Password buffer */
415
416 #ifndef NOHTTP
417 char * tcp_http_proxy = NULL; /* Name[:port] of http proxy server */
418 int tcp_http_proxy_errno = 0;
419 char * tcp_http_proxy_user = NULL;
420 char * tcp_http_proxy_pwd = NULL;
421 char * tcp_http_proxy_agent = NULL;
422 #define HTTPCPYL 1024
423 static char proxycopy[HTTPCPYL];
424 #endif /* NOHTTP */
425
426 #ifdef OS2
427 extern int tt_rows[], tt_cols[];
428 extern int tt_status[VNUM];
429 #else /* OS2 */
430 extern int tt_rows, tt_cols; /* Everybody has this */
431 #endif /* OS2 */
432
433 extern int cmd_cols, cmd_rows;
434
435 #ifdef STREAMING /* Use blocking writes for streaming */
436 extern int streaming;
437 #endif /* STREAMING */
438
439 #ifdef NT
440 extern int WSASafeToCancel;
441 int win95selectbug = 0; /* For TCP/IP stacks whose select() */
442 /* always fails on write requests such as Cisco and Quarterdeck */
443 #define stricmp _stricmp
444 #endif /* NT */
445
446 #ifndef NOTCPOPTS
447
448 /* Skip all this if NOTCPOPTS specified. */
449
450 #ifdef SOL_SOCKET
451
452 #ifdef TCP_NODELAY
453 int tcp_nodelay = 0; /* Nagle algorithm TCP_NODELAY */
454 #endif /* TCP_NODELAY */
455
456 #ifdef SO_DONTROUTE
457 int tcp_dontroute = 0;
458 #endif /* SO_DONTROUTE */
459
460 #ifdef SO_LINGER
461 int tcp_linger = 0; /* SO_LINGER */
462 int tcp_linger_tmo = 0; /* SO_LINGER timeout */
463 #endif /* SO_LINGER */
464
465 #ifdef HPUX /* But the data structures */
466 #ifndef HPUX8 /* needed for linger are not */
467 #ifndef HPUX9 /* defined in HP-UX versions */
468 #ifndef HPUX10 /* prior to 8.00. */
469 #ifdef SO_LINGER
470 #undef SO_LINGER
471 #endif /* SO_LINGER */
472 #endif /* HPUX10 */
473 #endif /* HPUX9 */
474 #endif /* HPUX8 */
475 #endif /* HPUX */
476
477 #ifndef SO_OOBINLINE /* Hopefully only HP-UX 7.0 */
478 #define SO_OOBINLINE 0x0100
479 #endif /* SO_OOBINLINE */
480
481 #ifndef TCPSNDBUFSIZ
482 #ifdef VMS
483 #ifdef __alpha
484 #define TCPSNDBUFSIZ 16384
485 #endif /* __alpha */
486 #endif /* VMS */
487 #endif /* TCPSNDBUFSIZ */
488
489 #ifndef TCPSNDBUFSIZ
490 #define TCPSNDBUFSIZ -1
491 #endif /* TCPSNDBUFSIZ */
492
493 #ifdef SO_SNDBUF
494 int tcp_sendbuf = TCPSNDBUFSIZ;
495 #endif /* SO_SNDBUF */
496
497 #ifdef SO_RCVBUF
498 int tcp_recvbuf = -1;
499 #endif /* SO_RCVBUF */
500
501 #ifdef SO_KEEPALIVE
502 int tcp_keepalive = 1;
503 #endif /* SO_KEEPALIVE */
504
505 #endif /* SOL_SOCKET */
506 #endif /* NOTCPOPTS */
507
508 #ifndef NETCONN
509 /*
510 Network support not defined.
511 Dummy functions here in case #ifdef's forgotten elsewhere.
512 */
513 int /* Open network connection */
netopen(name,lcl,nett)514 netopen(name, lcl, nett) char *name; int *lcl, nett; {
515 return(-1);
516 }
517 int /* Close network connection */
netclos()518 netclos() {
519 return(-1);
520 }
521 int /* Check network input buffer */
nettchk()522 nettchk() {
523 return(-1);
524 }
525 int /* Flush network input buffer */
netflui()526 netflui() {
527 return(-1);
528 }
529 int /* Send network BREAK */
netbreak()530 netbreak() {
531 return(-1);
532 }
533 int /* Input character from network */
netinc(timo)534 netinc(timo) int timo; {
535 return(-1);
536 }
537 int /* Output character to network */
538 #ifdef CK_ANSIC
nettoc(CHAR c)539 nettoc(CHAR c)
540 #else
541 nettoc(c) CHAR c;
542 #endif /* CK_ANSIC */
543 /* nettoc */ {
544 return(-1);
545 }
546 int
nettol(s,n)547 nettol(s,n) CHAR *s; int n; {
548 return(-1);
549 }
550
551 #else /* NETCONN is defined (much of this module...) */
552
553 #ifdef NETLEBUF
554 VOID
le_init()555 le_init() { /* LocalEchoInit() */
556 int i;
557 for (i = 0; i < LEBUFSIZ; i++)
558 le_buf[i] = '\0';
559 le_start = 0;
560 le_end = 0;
561 le_data = 0;
562 tt_push_inited = 1;
563 }
564
565 VOID
le_clean()566 le_clean() { /* LocalEchoCleanup() */
567 le_init();
568 return;
569 }
570
571 int
le_inbuf()572 le_inbuf() {
573 int rc = 0;
574 if (le_start != le_end) {
575 rc = (le_end -
576 le_start +
577 LEBUFSIZ) % LEBUFSIZ;
578 }
579 return(rc);
580 }
581
582 int
583 #ifdef CK_ANSIC
le_putchar(CHAR ch)584 le_putchar(CHAR ch)
585 #else
586 le_putchar(ch) CHAR ch;
587 #endif /* CK_ANSIC */
588 /* le_putchar */ {
589 if ((le_start - le_end + LEBUFSIZ)%LEBUFSIZ == 1) {
590 debug(F110,"le_putchar","buffer is full",0);
591 return(-1);
592 }
593 le_buf[le_end++] = ch;
594 if (le_end == LEBUFSIZ)
595 le_end = 0;
596 le_data = 1;
597 return(0);
598 }
599
600 int
601 #ifdef CK_ANSIC
le_puts(CHAR * s,int n)602 le_puts(CHAR * s, int n)
603 #else
604 le_puts(s,n) CHAR * s; int n;
605 #endif /* CK_ANSIC */
606 /* le_puts */ {
607 int rc = 0;
608 int i = 0;
609 CHAR * p = (CHAR *)"le_puts";
610 ckhexdump(p,s,n);
611 for (i = 0; i < n; i++)
612 rc = le_putchar((char)s[i]);
613 debug(F101,"le_puts","",rc);
614 return(rc);
615 }
616
617 int
618 #ifdef CK_ANSIC
le_putstr(CHAR * s)619 le_putstr(CHAR * s)
620 #else
621 le_putstr(s) CHAR * s;
622 #endif /* CK_ANSIC */
623 /* le_puts */ {
624 CHAR * p;
625 int rc = 0;
626 p = (CHAR *)"le_putstr";
627 ckhexdump(p,s,(int)strlen((char *)s));
628 for (p = s; *p && !rc; p++)
629 rc = le_putchar(*p);
630 return(rc);
631 }
632
633 int
634 #ifdef CK_ANSIC
le_getchar(CHAR * pch)635 le_getchar(CHAR * pch)
636 #else /* CK_ANSIC */
637 le_getchar(pch) CHAR * pch;
638 #endif /* CK_ANSIC */
639 /* le_gatchar */ {
640 int rc = 0;
641 if (le_start != le_end) {
642 *pch = le_buf[le_start];
643 le_buf[le_start] = 0;
644 le_start++;
645
646 if (le_start == LEBUFSIZ)
647 le_start = 0;
648
649 if (le_start == le_end) {
650 le_data = 0;
651 }
652 rc++;
653 } else {
654 *pch = 0;
655 }
656 return(rc);
657 }
658 #endif /* NETLEBUF */
659
660 #ifdef VMS
661 /*
662 In edit 190, we moved tn_ini() to be called from within netopen().
663 But tn_ini() calls ttol(), and ttol() checks to see if it's a net
664 connection, but the flag for that isn't set until after netopen()
665 is finished. Since, in this module, we are always doing network
666 output anyway, we just call nettol() directly, instead of going thru
667 ttol(). Only needed for VMS, since UNIX, AOS/VS, and VOS can handle
668 net connections just like regular connections in ttol(), and OS/2
669 has a special routine for this.
670 */
671 #define ttol nettol
672 #endif /* VMS */
673
674 int tcpsrfd = -1;
675
676 #ifdef CK_KERBEROS
677
678 char * krb5_d_principal = NULL; /* Default principal */
679 char * krb5_d_instance = NULL; /* Default instance */
680 char * krb5_d_realm = NULL; /* Default realm */
681 char * krb5_d_cc = NULL; /* Default credentials cache */
682 char * krb5_d_srv = NULL; /* Default Service */
683 int krb5_d_lifetime = 600; /* Default lifetime (10 hours) */
684 int krb5_d_forwardable = 0; /* creds not forwardable */
685 int krb5_d_proxiable = 0; /* creds not proxiable */
686 int krb5_d_renewable = 0; /* creds not renewable (0 min) */
687 int krb5_autoget = 1; /* Autoget TGTs */
688 int krb5_autodel = 0; /* Auto delete TGTs */
689 int krb5_d_getk4 = 0; /* K5 Kinit gets K4 TGTs */
690 int krb5_checkaddrs = 1; /* Check TGT Addrs */
691 int krb5_d_no_addresses = 0; /* Do not include IP Addresses */
692 char * krb5_d_addrs[KRB5_NUM_OF_ADDRS+1]={NULL,NULL}; /* Addrs to include */
693 int krb5_errno = 0; /* Last K5 errno */
694 char * krb5_errmsg = NULL; /* Last K5 errmsg */
695 char * k5_keytab = NULL;
696
697 char * krb4_d_principal = NULL; /* Default principal */
698 char * krb4_d_realm = NULL; /* Default realm */
699 char * krb4_d_srv = NULL; /* Default Service */
700 int krb4_d_lifetime = 600; /* Default lifetime (10 hours) */
701 int krb4_d_preauth = 1; /* Use preauth requests */
702 char * krb4_d_instance = NULL; /* Default instance */
703 int krb4_autoget = 1; /* Autoget TGTs */
704 int krb4_autodel = 0; /* Auto delete TGTs */
705 int krb4_checkaddrs = 1; /* Check TGT Addrs */
706 char * k4_keytab = NULL;
707
708 int krb4_errno = 0; /* Last K4 errno */
709 char * krb4_errmsg = NULL; /* Last K4 errmsg */
710
711 struct krb_op_data krb_op = { /* Operational data structure */
712 0, NULL /* (version, cachefile) */
713 };
714
715 struct krb4_init_data krb4_init = { /* Kerberos 4 INIT data structure */
716 0, NULL, NULL, NULL, NULL
717 };
718
719 struct krb5_init_data krb5_init = { /* Kerberos 5 INIT data structure */
720 0, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, 0, 0, 0,
721 { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
722 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
723 0
724 };
725
726 struct krb5_list_cred_data krb5_lc = { /* List Credentials data structure */
727 0, 0, 0
728 };
729
730 int krb_action = -1; /* Kerberos action to perform */
731
732 #ifndef CK_AUTHENTICATION
733 char *
ck_krb4_getrealm()734 ck_krb4_getrealm() {
735 return("");
736 }
737 char *
ck_krb5_getrealm(cc)738 ck_krb5_getrealm(cc) char * cc; {
739 return("");
740 }
741 char *
ck_krb4_getprincipal()742 ck_krb4_getprincipal() {
743 return("");
744 }
745 char *
ck_krb5_getprincipal(cc)746 ck_krb5_getprincipal(cc) char * cc; {
747 return("");
748 }
749 #endif /* CK_AUTHENTICATION */
750
751 /* I N I _ K E R B -- Initialize Kerberos data */
752
753 VOID
ini_kerb()754 ini_kerb() {
755 int i;
756
757 krb_action = -1; /* No action specified */
758
759 krb_op.version = 0; /* Kerberos version (none) */
760 krb_op.cache = NULL; /* Cache file (none) */
761
762 /* Kerberos 5 */
763
764 krb5_init.forwardable = krb5_d_forwardable; /* Init switch values... */
765 krb5_init.proxiable = krb5_d_proxiable;
766 krb5_init.lifetime = krb5_d_lifetime;
767 krb5_init.renew = 0;
768 krb5_init.renewable = krb5_d_renewable;
769 krb5_init.validate = 0;
770 krb5_init.no_addresses = krb5_d_no_addresses;
771 krb5_init.getk4 = krb5_d_getk4;
772 if (krb5_init.postdate) {
773 free(krb5_init.postdate);
774 krb5_init.postdate = NULL;
775 }
776 if (krb5_init.service) {
777 free(krb5_init.service);
778 krb5_init.service = NULL;
779 }
780 if (!krb5_d_cc || !krb5_d_cc[0]) { /* Set default cache */
781 char * p;
782 p = ck_krb5_get_cc_name();
783 makestr(&krb5_d_cc,(p && p[0]) ? p : NULL);
784 }
785 if (!krb5_d_realm || !krb5_d_realm[0]) { /* Set default realm */
786 char * p;
787 p = ck_krb5_getrealm(krb5_d_cc);
788 makestr(&krb5_d_realm,(p && p[0]) ? p : NULL);
789 }
790 makestr(&krb5_init.instance,krb5_d_instance);
791 makestr(&krb5_init.realm,krb5_d_realm); /* Set realm from default */
792 if (krb5_init.password) {
793 memset(krb5_init.password,0xFF,strlen(krb5_init.password));
794 free(krb5_init.password);
795 krb5_init.password = NULL;
796 }
797 if (!krb5_d_principal) { /* Default principal */
798 /* a Null principal indicates the user should be prompted */
799 char * p = ck_krb5_getprincipal(krb5_d_cc);
800 if (!p || !(*p))
801 p = (char *)uidbuf; /* Principal = user */
802 makestr(&krb5_d_principal,(p && p[0]) ? p : NULL);
803 }
804 makestr(&krb5_init.principal,krb5_d_principal);
805 for (i = 0; i <= KRB5_NUM_OF_ADDRS; i++) {
806 if (krb5_init.addrs[i])
807 free(krb5_init.addrs[i]);
808 krb5_init.addrs[i] = NULL;
809 }
810 for (i = 0; i <= KRB5_NUM_OF_ADDRS && krb5_d_addrs[i]; i++) {
811 makestr(&krb5_init.addrs[i],krb5_d_addrs[i]);
812 }
813
814 /* Kerberos 4 */
815
816 krb4_init.lifetime = krb4_d_lifetime;
817 krb4_init.preauth = krb4_d_preauth;
818 makestr(&krb4_init.instance,krb4_d_instance);
819 if (!krb4_d_realm || !krb4_d_realm[0]) {/* Set default realm */
820 char * p;
821 p = ck_krb4_getrealm();
822 makestr(&krb4_d_realm,(p && p[0]) ? p : NULL);
823 }
824 makestr(&krb4_init.realm,krb4_d_realm);
825 if (krb4_init.password) {
826 memset(krb4_init.password,0xFF,strlen(krb4_init.password));
827 free(krb4_init.password);
828 krb4_init.password = NULL;
829 }
830 if (!krb4_d_principal) { /* Default principal */
831 /* a Null principal indicates the user should be prompted */
832 char * p = ck_krb4_getprincipal();
833 if (!p || !(*p))
834 p = (char *)uidbuf; /* Principal = user */
835 makestr(&(krb4_d_principal),(p && p[0]) ? p : NULL);
836 }
837 makestr(&(krb4_init.principal),krb4_d_principal);
838 }
839
840 /* D O A U T H -- AUTHENTICATE action routine */
841
842 int
doauth(cx)843 doauth(cx) int cx; { /* AUTHENTICATE action routine */
844 int rc = 0; /* Return code */
845
846 #ifdef CK_AUTHENTICATION
847 #ifdef OS2
848 if (!ck_security_loaddll()) /* Load various DLLs */
849 return(rc);
850 #endif /* OS2 */
851 if (krb_op.version == 4) { /* Version = 4 */
852 #ifdef COMMENT
853 sho_auth(AUTHTYPE_KERBEROS_V4);
854 #endif /* COMMENT */
855 if (!ck_krb4_is_installed()) {
856 printf("?Kerberos 4 is not installed\n");
857 return(0);
858 }
859 switch (krb_action) { /* Perform V4 functions */
860 case KRB_A_IN: /* INIT */
861 rc |= !(ck_krb4_initTGT(&krb_op,&krb4_init) < 0);
862 break;
863 case KRB_A_DE: /* DESTROY */
864 rc |= !(ck_krb4_destroy(&krb_op) < 0);
865 break;
866 case KRB_A_LC: /* LIST-CREDENTIALS */
867 rc |= !(ck_krb4_list_creds(&krb_op) < 0);
868 break;
869 }
870 }
871 if (krb_op.version == 5) { /* V5 functions */
872 #ifdef COMMENT
873 sho_auth(AUTHTYPE_KERBEROS_V5);
874 #endif /* COMMENT */
875 if (!ck_krb5_is_installed()) {
876 printf("?Kerberos 5 is not installed\n");
877 return(0);
878 }
879 switch (krb_action) {
880 case KRB_A_IN: /* INIT */
881 rc |= !(ck_krb5_initTGT(&krb_op,&krb5_init,
882 krb5_init.getk4 ? &krb4_init : 0) < 0);
883 break;
884 case KRB_A_DE: /* DESTROY */
885 rc |= !(ck_krb5_destroy(&krb_op) < 0);
886 break;
887 case KRB_A_LC: /* LIST-CREDENTIALS */
888 if (krb_op.version == 0)
889 printf("\n");
890 rc |= !(ck_krb5_list_creds(&krb_op,&krb5_lc) < 0);
891 break;
892 }
893 }
894 #else
895 #ifndef NOICP
896 #ifndef NOSHOW
897 rc = sho_auth(0); /* Show all */
898 #endif /* NOSHOW */
899 #endif /* NOICP */
900 #endif /* CK_AUTHENTICATION */
901 return(rc);
902 }
903 #endif /* CK_KERBEROS */
904
905 #ifdef TCPSOCKET
906 #ifndef OS2
907 #ifndef NOLISTEN /* For incoming connections */
908
909 #ifndef INADDR_ANY
910 #define INADDR_ANY 0
911 #endif /* INADDR_ANY */
912
913 _PROTOTYP( int ttbufr, ( VOID ) );
914 _PROTOTYP( int tcpsrv_open, (char *, int *, int, int ) );
915
916 static unsigned short tcpsrv_port = 0;
917
918 #endif /* NOLISTEN */
919 #endif /* OS2 */
920
921 static char svcbuf[80]; /* TCP service string */
922 static int svcnum = 0; /* TCP port number */
923
924 #endif /* TCPSOCKET */
925
926 /*
927 TCPIPLIB means use separate socket calls for i/o, while on UNIX the
928 normal file system calls are used for TCP/IP sockets too.
929 Means "DEC_TCPIP or MULTINET or WINTCP or OS2 or BEBOX" (see ckcnet.h),
930 */
931
932 #ifdef TCPIPLIB
933
934 /* For buffered network reads... */
935 /*
936 If the buffering code is written right, it shouldn't matter
937 how long this buffer is.
938 */
939 #ifdef OS2
940 #ifdef NT
941 #define TTIBUFL 64240 /* 44 * 1460 (MSS) */
942 #else
943 #define TTIBUFL 32120 /* 22 * 1460 (MSS) */
944 #endif /* NT */
945 #else /* OS2 */
946 #define TTIBUFL 8191 /* Let's use 8K. */
947 #endif /* OS2 */
948
949 CHAR ttibuf[TTIBUFL+1];
950
951 /*
952 select() is used in preference to alarm()/signal(), but different systems
953 use different forms of select()...
954 */
955 #ifndef NOSELECT /* Option to override BSDSELECT */
956 #ifdef BELLV10
957 /*
958 Note: Although BELLV10 does have TCP/IP support, and does use the unique
959 form of select() that is evident in this module (and in ckutio.c), it does
960 not have a sockets library and so we can't build Kermit TCP/IP support for
961 it. For this, somebody would have to write TCP/IP streams code.
962 */
963 #define BELLSELECT
964 #ifndef FD_SETSIZE
965 #define FD_SETSIZE 128
966 #endif /* FD_SETSIZE */
967 #else
968 #ifdef WINTCP /* VMS with Wollongong WIN/TCP */
969 #ifndef OLD_TWG /* TWG 3.2 has only select(read) */
970 #define BSDSELECT
971 #endif /* OLD_TWG */
972 #else
973 #ifdef CMU_TCPIP /* LIBCMU can do select */
974 #define BSDSELECT
975 #else
976 #ifdef DEC_TCPIP
977 #define BSDSELECT
978 #else
979 #ifdef OS2 /* OS/2 with TCP/IP */
980 #ifdef NT
981 #define BSDSELECT
982 #else /* NT */
983 #define IBMSELECT
984 #endif /* NT */
985 #endif /* OS2 */
986 #endif /* DEC_TCPIP */
987 #endif /* CMU_TCPIP */
988 #endif /* WINTCP */
989 #endif /* BELLV10 */
990 #endif /* NOSELECT */
991 /*
992 Others (TGV, TCPware, ...) use alarm()/signal(). The BSDSELECT case does not
993 compile at all; the IBMSELECT case compiles and links but crashes at runtime.
994 NOTE: If any of these can be converted to select(), they should be for two
995 reasons: (1) It's a lot faster; (2) certain sockets libraries do not like
996 their socket_read() calls to be interrupted; subsequent socket_read()'s tend
997 to fail with EBUSY. This happened in the UCX case before it was converted
998 to use select().
999 */
1000 #ifndef OS2
1001 #ifndef VMS
1002 static /* These are used in CKVTIO.C */
1003 #endif /* VMS */ /* And in CKONET.C */
1004 #endif /* OS2 */
1005 int
1006 ttibp = 0,
1007 ttibn = 0;
1008 /*
1009 Read bytes from network into internal buffer ttibuf[].
1010 To be called when input buffer is empty, i.e. when ttibn == 0.
1011
1012 Other network reading routines, like ttinc, ttinl, ttxin, should check the
1013 internal buffer first, and call this routine for a refill if necessary.
1014
1015 Returns -1 on error, 0 if nothing happens. When data is read successfully,
1016 returns number of bytes read, and sets global ttibn to that number and
1017 ttibp (the buffer pointer) to zero.
1018 */
1019 _PROTOTYP( int ttbufr, ( VOID ) );
1020 int
ttbufr()1021 ttbufr() { /* TT Buffer Read */
1022 int count;
1023
1024 if (ttnet != NET_TCPB) /* First make sure current net is */
1025 return(-1); /* TCP/IP; if not, do nothing. */
1026
1027 #ifdef OS2
1028 RequestTCPIPMutex(SEM_INDEFINITE_WAIT);
1029 #endif /* OS2 */
1030
1031 if (ttibn > 0) { /* Our internal buffer is not empty, */
1032 #ifdef OS2
1033 ReleaseTCPIPMutex();
1034 #endif /* OS2 */
1035 return(ttibn); /* so keep using it. */
1036 }
1037
1038 if (ttyfd == -1) { /* No connection, error */
1039 #ifdef OS2
1040 ReleaseTCPIPMutex();
1041 #endif /* OS2 */
1042 return(-2);
1043 }
1044
1045 ttibp = 0; /* Else reset pointer to beginning */
1046
1047 #ifdef WINTCP
1048 count = 512; /* This works for WIN/TCP */
1049 #else
1050 #ifdef DEC_TCPIP
1051 count = 512; /* UCX */
1052 #else
1053 #ifdef OS2
1054 count = TTIBUFL;
1055 #else /* Multinet, etc. */
1056 count = ttchk(); /* Check network input buffer, */
1057 if (ttibn > 0) { /* which can put a char there! */
1058 debug(F111,"ttbufr","ttchk() returns",count);
1059 #ifdef OS2
1060 ReleaseTCPIPMutex();
1061 #endif /* OS2 */
1062 return(ttibn);
1063 }
1064 if (count < 0) { /* Read error - connection closed */
1065 #ifdef OS2
1066 ReleaseTCPIPMutex();
1067 #endif /* OS2 */
1068 return(-2);
1069 }
1070 else if (count > TTIBUFL) /* Too many to read */
1071 count = TTIBUFL;
1072 else if (count == 0) /* None, so force blocking read */
1073 count = 1;
1074 #endif /* OS2 */
1075 #endif /* DEC_TCPIP */
1076 #endif /* WINTCP */
1077 debug(F101,"ttbufr count 1","",count);
1078
1079 #ifdef CK_SSL
1080 if (ssl_active_flag || tls_active_flag) {
1081 int error;
1082 ssl_read:
1083 if (ssl_active_flag)
1084 count = SSL_read(ssl_con, ttibuf, count);
1085 else
1086 count = SSL_read(tls_con, ttibuf, count);
1087 error = SSL_get_error(ssl_active_flag?ssl_con:tls_con,count);
1088 switch (error) {
1089 case SSL_ERROR_NONE:
1090 debug(F111,"ttbufr SSL_ERROR_NONE","count",count);
1091 if (count > 0) {
1092 ttibp = 0; /* Reset buffer pointer. */
1093 ttibn = count;
1094 #ifdef OS2
1095 ReleaseTCPIPMutex();
1096 #endif /* OS2 */
1097 return(ttibn); /* Return buffer count. */
1098 } else if (count < 0) {
1099 #ifdef OS2
1100 ReleaseTCPIPMutex();
1101 #endif /* OS2 */
1102 return(-1);
1103 } else {
1104 netclos();
1105 #ifdef OS2
1106 ReleaseTCPIPMutex();
1107 #endif /* OS2 */
1108 return(-2);
1109 }
1110 case SSL_ERROR_WANT_WRITE:
1111 debug(F100,"ttbufr SSL_ERROR_WANT_WRITE","",0);
1112 #ifdef OS2
1113 ReleaseTCPIPMutex();
1114 #endif /* OS2 */
1115 return(-1);
1116 case SSL_ERROR_WANT_READ:
1117 debug(F100,"ttbufr SSL_ERROR_WANT_READ","",0);
1118 #ifdef OS2
1119 ReleaseTCPIPMutex();
1120 #endif /* OS2 */
1121 return(-1);
1122 case SSL_ERROR_SYSCALL:
1123 if ( count == 0 ) { /* EOF */
1124 netclos();
1125 #ifdef OS2
1126 ReleaseTCPIPMutex();
1127 #endif /* OS2 */
1128 return(-2);
1129 } else {
1130 int rc = -1;
1131 #ifdef NT
1132 int gle = GetLastError();
1133 debug(F111,"ttbufr SSL_ERROR_SYSCALL",
1134 "GetLastError()",gle);
1135 rc = os2socketerror(gle);
1136 if (rc == -1)
1137 rc = -2;
1138 else if ( rc == -2 )
1139 rc = -1;
1140 #endif /* NT */
1141 #ifdef OS2
1142 ReleaseTCPIPMutex();
1143 #endif /* OS2 */
1144 return(rc);
1145 }
1146 case SSL_ERROR_WANT_X509_LOOKUP:
1147 debug(F100,"ttbufr SSL_ERROR_WANT_X509_LOOKUP","",0);
1148 netclos();
1149 #ifdef OS2
1150 ReleaseTCPIPMutex();
1151 #endif /* OS2 */
1152 return(-2);
1153 case SSL_ERROR_SSL:
1154 if (bio_err!=NULL) {
1155 int len;
1156 extern char ssl_err[];
1157 BIO_printf(bio_err,"ttbufr SSL_ERROR_SSL\n");
1158 ERR_print_errors(bio_err);
1159 len = BIO_read(bio_err,ssl_err,SSL_ERR_BFSZ);
1160 ssl_err[len < SSL_ERR_BFSZ ? len : SSL_ERR_BFSZ] = '\0';
1161 debug(F110,"ttbufr SSL_ERROR_SSL",ssl_err,0);
1162 if (ssl_debug_flag)
1163 printf(ssl_err);
1164 } else if (ssl_debug_flag) {
1165 debug(F100,"ttbufr SSL_ERROR_SSL","",0);
1166 fflush(stderr);
1167 fprintf(stderr,"ttbufr SSL_ERROR_SSL\n");
1168 ERR_print_errors_fp(stderr);
1169 }
1170 #ifdef COMMENT
1171 netclos();
1172 #endif /* COMMENT */
1173 #ifdef OS2
1174 ReleaseTCPIPMutex();
1175 #endif /* OS2 */
1176 return(-2);
1177 case SSL_ERROR_ZERO_RETURN:
1178 debug(F100,"ttbufr SSL_ERROR_ZERO_RETURN","",0);
1179 netclos();
1180 #ifdef OS2
1181 ReleaseTCPIPMutex();
1182 #endif /* OS2 */
1183 return(-2);
1184 default:
1185 debug(F100,"ttbufr SSL_ERROR_?????","",0);
1186 netclos();
1187 #ifdef OS2
1188 ReleaseTCPIPMutex();
1189 #endif /* OS2 */
1190 return(-2);
1191 }
1192 }
1193 #endif /* CK_SSL */
1194
1195 #ifdef COMMENT
1196 /*
1197 This is for nonblocking reads, which we don't do any more. This code didn't
1198 work anyway, in the sense that a broken connection was never sensed.
1199 */
1200 if ((count = socket_read(ttyfd,&ttibuf[ttibp+ttibn],count)) < 1) {
1201 if (count == -1 && socket_errno == EWOULDBLOCK) {
1202 debug(F100,"ttbufr finds nothing","",0);
1203 #ifdef OS2
1204 ReleaseTCPIPMutex();
1205 #endif /* OS2 */
1206 return(0);
1207 } else {
1208 debug(F101,"ttbufr socket_read error","",socket_errno);
1209 #ifdef OS2
1210 ReleaseTCPIPMutex();
1211 #endif /* OS2 */
1212 return(-1);
1213 }
1214
1215 } else if (count == 0) {
1216 debug(F100,"ttbufr socket eof","",0);
1217 #ifdef OS2
1218 ReleaseTCPIPMutex();
1219 #endif /* OS2 */
1220 return(-1);
1221 }
1222 #else /* COMMENT */
1223
1224 /* This is for blocking reads */
1225
1226 #ifndef VMS
1227 #ifdef SO_OOBINLINE
1228 {
1229 int outofband = 0;
1230 #ifdef BELLSELECT
1231 if (select(128, NULL, NULL, efds, 0) > 0 && FD_ISSET(ttyfd, efds))
1232 outofband = 1;
1233 #else
1234 #ifdef BSDSELECT
1235 fd_set efds;
1236 struct timeval tv;
1237 FD_ZERO(&efds);
1238 FD_SET(ttyfd, &efds);
1239 tv.tv_sec = tv.tv_usec = 0L;
1240 debug(F100,"Out-of-Band BSDSELECT","",0);
1241 #ifdef NT
1242 WSASafeToCancel = 1;
1243 #endif /* NT */
1244 if (select(FD_SETSIZE, NULL, NULL, &efds, &tv) > 0 &&
1245 FD_ISSET(ttyfd, &efds))
1246 outofband = 1;
1247 #ifdef NT
1248 WSASafeToCancel = 0;
1249 #endif /* NT */
1250 #else /* !BSDSELECT */
1251 #ifdef IBMSELECT
1252 /* Is used by OS/2 ... */
1253 /* ... and it came in handy! For our TCP/IP layer, it avoids all the fd_set */
1254 /* and timeval stuff since this is the only place where it is used. */
1255 int socket = ttyfd;
1256 debug(F100,"Out-of-Band IBMSELECT","",0);
1257 if ((select(&socket, 0, 0, 1, 0L) == 1) && (socket == ttyfd))
1258 outofband = 1;
1259 #else /* !IBMSELECT */
1260 /*
1261 If we can't use select(), then we use the regular alarm()/signal()
1262 timeout mechanism.
1263 */
1264 debug(F101,"Out-of-Band data not supported","",0);
1265 outofband = 0;
1266
1267 #endif /* IBMSELECT */
1268 #endif /* BSDSELECT */
1269 #endif /* BELLSELECT */
1270 if (outofband) {
1271 /* Get the Urgent Data */
1272 /* if OOBINLINE is disabled this should be only a single byte */
1273 /* MS Winsock has a bug in Windows 95. Extra bytes are delivered */
1274 /* That were never sent. */
1275 #ifdef OS2
1276 RequestTCPIPMutex(SEM_INDEFINITE_WAIT);
1277 #endif /* OS2 */
1278 count = socket_recv(ttyfd,&ttibuf[ttibp+ttibn],count,MSG_OOB);
1279 #ifdef OS2
1280 ReleaseTCPIPMutex();
1281 #endif /* OS2 */
1282 if (count <= 0) {
1283 int s_errno = socket_errno;
1284 debug(F101, "ttbufr socket_recv MSG_OOB","",count);
1285 debug(F101, "ttbufr socket_errno","",s_errno);
1286 #ifdef OS2ONLY
1287 if (count < 0 && (s_errno == 0 || s_errno == 23)) {
1288 /* These appear in OS/2 - don't know why */
1289 /* ignore it and read as normal data */
1290 /* and break, then we will attempt to read */
1291 /* the port using normal read() techniques */
1292 debug(F100,"ttbufr handing as in-band data","",0);
1293 count = 1;
1294 } else {
1295 netclos(); /* *** *** */
1296 #ifdef OS2
1297 ReleaseTCPIPMutex();
1298 #endif /* OS2 */
1299 return(-2);
1300 }
1301 #else /* OS2ONLY */
1302 netclos(); /* *** *** */
1303 #ifdef OS2
1304 ReleaseTCPIPMutex();
1305 #endif /* OS2 */
1306 return(-2);
1307 #endif /* OS2ONLY */
1308 } else { /* we got out-of-band data */
1309 ckhexdump("ttbufr out-of-band chars",&ttibuf[ttibp+ttibn],count);
1310 #ifdef BETADEBUG
1311 bleep(BP_NOTE);
1312 #endif /* BETADEBUG */
1313 #ifdef RLOGCODE /* blah */
1314 if (ttnproto == NP_RLOGIN ||
1315 ttnproto == NP_K4LOGIN || ttnproto == NP_EK4LOGIN ||
1316 ((ttnproto == NP_K5LOGIN || ttnproto == NP_EK5LOGIN) &&
1317 !rlog_inband)
1318 )
1319 {
1320 /*
1321 When urgent data is read with MSG_OOB and not OOBINLINE
1322 then urgent data and normal data are not mixed. So
1323 treat the entire buffer as urgent data.
1324 */
1325 rlog_oob(&ttibuf[ttibp+ttibn], count);
1326 #ifdef OS2
1327 ReleaseTCPIPMutex();
1328 #endif /* OS2 */
1329 return ttbufr();
1330 } else
1331 #endif /* RLOGCODE */ /* blah */
1332 #ifdef COMMENT
1333 /*
1334 I haven't written this yet, nor do I know what it should do
1335 */
1336 if (ttnproto == NP_TELNET) {
1337 tn_oob();
1338 #ifdef OS2
1339 ReleaseTCPIPMutex();
1340 #endif /* OS2 */
1341 return 0;
1342 } else
1343 #endif /* COMMENT */
1344 {
1345 /* For any protocols we don't have a special out-of-band */
1346 /* handler for, just put the bytes in the normal buffer */
1347 /* and return */
1348
1349 ttibp += 0; /* Reset buffer pointer. */
1350 ttibn += count;
1351 #ifdef DEBUG
1352 /* Got some bytes. */
1353 debug(F101,"ttbufr count 2","",count);
1354 if (count > 0)
1355 ttibuf[ttibp+ttibn] = '\0';
1356 debug(F111,"ttbufr ttibuf",ttibuf,ttibp);
1357 #endif /* DEBUG */
1358 #ifdef OS2
1359 ReleaseTCPIPMutex();
1360 #endif /* OS2 */
1361 return(ttibn); /* Return buffer count. */
1362 }
1363 }
1364 }
1365 }
1366 #endif /* SO_OOBINLINE */
1367 #endif /* VMS */
1368
1369 count = socket_read(ttyfd,&ttibuf[ttibp+ttibn],count);
1370 if (count <= 0) {
1371 int s_errno = socket_errno;
1372 debug(F101,"ttbufr socket_read","",count);
1373 debug(F101,"ttbufr socket_errno","",s_errno);
1374 #ifdef OS2
1375 if (count == 0 || os2socketerror(s_errno) < 0) {
1376 netclos();
1377 ReleaseTCPIPMutex();
1378 return(-2);
1379 }
1380 ReleaseTCPIPMutex();
1381 return(-1);
1382 #else /* OS2 */
1383 netclos(); /* *** *** */
1384 return(-2);
1385 #endif /* OS2 */
1386 }
1387 #endif /* COMMENT */ /* (blocking vs nonblock reads...) */
1388 else {
1389 ttibp = 0; /* Reset buffer pointer. */
1390 ttibn += count;
1391 #ifdef DEBUG
1392 debug(F101,"ttbufr count 2","",count); /* Got some bytes. */
1393 if (count > 0)
1394 ttibuf[ttibp+ttibn] = '\0';
1395 debug(F111,"ttbufr ttibuf",&ttibuf[ttibp],ttibn);
1396 #endif /* DEBUG */
1397
1398 #ifdef OS2
1399 ReleaseTCPIPMutex();
1400 #endif /* OS2 */
1401 return(ttibn); /* Return buffer count. */
1402 }
1403 }
1404 #endif /* TCPIPLIB */
1405
1406 #ifndef IBMSELECT
1407 #ifndef BELLSELECT
1408 #ifndef BSDSELECT /* Non-TCPIPLIB case */
1409 #ifdef SELECT
1410 #define BSDSELECT
1411 #endif /* SELECT */
1412 #endif /* BSDSELECT */
1413 #endif /* BELLSELECT */
1414 #endif /* IBMSELECT */
1415
1416 #define TELNET_PORT 23 /* Should do lookup, but it won't change */
1417 #define RLOGIN_PORT 513
1418 #define KERMIT_PORT 1649
1419 #define KLOGIN_PORT 543
1420 #define EKLOGIN_PORT 2105
1421
1422 #ifndef NONET
1423 /*
1424 C-Kermit network open/close functions for BSD-sockets.
1425 Much of this code shared by SunLink X.25, which also uses the socket library.
1426 */
1427
1428 /* N E T O P N -- Open a network connection. */
1429 /*
1430 Call with:
1431 name of host (or host:service),
1432 lcl - local-mode flag to be set if this function succeeds,
1433 network type - value defined in ckunet.h.
1434 */
1435 #ifdef TCPSOCKET
1436 struct hostent *
1437 #ifdef CK_ANSIC
ck_copyhostent(struct hostent * h)1438 ck_copyhostent(struct hostent * h)
1439 #else /* CK_ANSIC */
1440 ck_copyhostent(h) struct hostent * h;
1441 #endif /* CK_ANSIC */
1442 {
1443 /*
1444 * The hostent structure is dynamic in nature.
1445 * struct hostent {
1446 * char * h_name;
1447 * char * * h_aliases;
1448 * short h_addrtype;
1449 * short h_length;
1450 * char * * h_addr_list;
1451 * #define h_addr h_addr_list[0]
1452 */
1453 #define HOSTENTCNT 5
1454 static struct hostent hosts[HOSTENTCNT] = {{NULL,NULL,0,0,NULL},
1455 {NULL,NULL,0,0,NULL},
1456 {NULL,NULL,0,0,NULL},
1457 {NULL,NULL,0,0,NULL},
1458 {NULL,NULL,0,0,NULL}};
1459 static int next = 0;
1460 int i,cnt;
1461 char ** pp;
1462
1463 if ( h == NULL )
1464 return(NULL);
1465
1466 if (next == HOSTENTCNT)
1467 next = 0;
1468
1469 if ( hosts[next].h_name ) {
1470 free(hosts[next].h_name);
1471 hosts[next].h_name = NULL;
1472 }
1473 if ( hosts[next].h_aliases ) {
1474 pp = hosts[next].h_aliases;
1475 while ( *pp ) {
1476 free(*pp);
1477 pp++;
1478 }
1479 free(hosts[next].h_aliases);
1480 }
1481 #ifdef HADDRLIST
1482 if ( hosts[next].h_addr_list ) {
1483 pp = hosts[next].h_addr_list;
1484 while ( *pp ) {
1485 free(*pp);
1486 pp++;
1487 }
1488 free(hosts[next].h_addr_list);
1489 }
1490 #endif /* HADDRLIST */
1491
1492 makestr(&hosts[next].h_name,h->h_name);
1493 if (h->h_aliases) {
1494 for ( cnt=0,pp=h->h_aliases; pp && *pp; pp++,cnt++) ;
1495 /* The following can give warnings in non-ANSI builds */
1496 hosts[next].h_aliases = (char **) malloc(sizeof(char *) * (cnt+1));
1497 for ( i=0; i<cnt; i++) {
1498 hosts[next].h_aliases[i] = NULL;
1499 makestr(&hosts[next].h_aliases[i],h->h_aliases[i]);
1500 }
1501 hosts[next].h_aliases[i] = NULL;
1502 } else
1503 hosts[next].h_aliases = NULL;
1504
1505 hosts[next].h_addrtype = h->h_addrtype;
1506 hosts[next].h_length = h->h_length;
1507
1508 #ifdef HADDRLIST
1509 #ifdef h_addr
1510 if (h->h_addr_list) {
1511 for ( cnt=0,pp=h->h_addr_list; pp && *pp; pp++,cnt++) ;
1512 /* The following can give warnings non-ANSI builds */
1513 hosts[next].h_addr_list = (char **) malloc(sizeof(char *) * (cnt+1));
1514 for ( i=0; i<cnt; i++) {
1515 hosts[next].h_addr_list[i] = malloc(h->h_length);
1516 bcopy(h->h_addr_list[i],hosts[next].h_addr_list[i],h->h_length);
1517 }
1518 hosts[next].h_addr_list[i] = NULL;
1519 } else
1520 hosts[next].h_addr_list = NULL;
1521 #else
1522 bcopy(h->h_addr, &hosts[next].h_addr, h->h_length);
1523 #endif /* h_addr */
1524 #else /* HADDRLIST */
1525 bcopy(h->h_addr, &hosts[next].h_addr, h->h_length);
1526 #endif /* HADDRLIST */
1527
1528 return(&hosts[next++]);
1529 }
1530
1531 #ifdef EXCELAN
1532 /*
1533 Most other BSD sockets implementations define these in header files
1534 and libraries.
1535 */
1536 struct servent {
1537 unsigned short s_port;
1538 };
1539
1540 struct hostent {
1541 short h_addrtype;
1542 struct in_addr h_addr;
1543 int h_length;
1544 };
1545
1546 struct servent *
getservbyname(service,connection)1547 getservbyname(service, connection) char *service,*connection; {
1548 static struct servent servrec;
1549 int port;
1550
1551 port = 0;
1552 if (strcmp(service, "telnet") == 0) port = 23;
1553 else if (strcmp(service, "smtp") == 0) port = 25;
1554 else port = atoi(service);
1555
1556 debug(F101,"getservbyname return port ","",port);
1557
1558 if (port > 0) {
1559 servrec.s_port = htons(port);
1560 return(&servrec);
1561 }
1562 return((struct servent *) NULL);
1563 }
1564
1565 struct hostent *
gethostbyname(hostname)1566 gethostbyname(hostname) char *hostname; {
1567 return((struct hostent *) NULL);
1568 }
1569
1570 unsigned long
inet_addr(name)1571 inet_addr(name) char *name; {
1572 unsigned long addr;
1573
1574 addr = rhost(&name);
1575 debug(F111,"inet_addr ",name,(int)addr);
1576 return(addr);
1577 }
1578
1579 char *
inet_ntoa(in)1580 inet_ntoa(in) struct in_addr in; {
1581 static char name[80];
1582 ckmakxmsg(name, ckuitoa(in.s_net),".",ckuitoa(in.s_host),".",
1583 ckuitoa(in.s_lh),".", ckuitoa(in.s_impno));
1584 return(name);
1585 }
1586 #else
1587 #ifdef DEC_TCPIP /* UCX */
1588
1589 int ucx_port_bug = 0; /* Explained below */
1590
1591 #ifdef OLDIP /* Very old VAXC or GCC */
1592 /*
1593 Note that my oldest VAX C (V3.1-051) does not need (or want) OLDIP,
1594 hence the "Very old" in the comment - SMS, 2010/03/15.
1595 */
1596 #define getservbyname my_getservbyname
1597
1598 #ifdef CK_ANSIC
1599 globalref int (*C$$GA_UCX_GETSERVBYNAME)();
1600 extern void C$$TRANSLATE();
1601 extern void C$$SOCK_TRANSLATE();
1602 #else
1603 globalref int (*C$$GA_UCX_GETSERVBYNAME)();
1604 extern VOID C$$TRANSLATE();
1605 extern VOID C$$SOCK_TRANSLATE();
1606 #endif /* CK_ANSIC */
1607
1608 struct servent *
my_getservbyname(service,proto)1609 my_getservbyname (service, proto) char *service, *proto; {
1610 static struct servent sent;
1611 struct iosb {
1612 union {
1613 unsigned long status;
1614 unsigned short st[2];
1615 } sb;
1616 unsigned long spare;
1617 } s;
1618 struct {
1619 struct iosb *s;
1620 char *serv;
1621 char *prot;
1622 } par;
1623 unsigned long e;
1624 char sbuf[30], pbuf[30];
1625 char *p;
1626
1627 debug(F111,"UCX getservbyname",service,(int)C$$GA_UCX_GETSERVBYNAME);
1628
1629 p = sbuf;
1630 ckstrncpy(p, service, 29);
1631 while (*p = toupper(*p), *p++) {}
1632 p = pbuf;
1633 ckstrncpy(p, proto, 29);
1634 while (*p = toupper(*p), *p++) {}
1635
1636 par.s = &s;
1637
1638 par.serv = "";
1639 par.prot = "";
1640 /* reset file pointer or something like that!?!? */
1641 e = (*C$$GA_UCX_GETSERVBYNAME)(&par, &sent, par.s);
1642 par.serv = sbuf;
1643 par.prot = pbuf; /* that is don't care */
1644 e = (*C$$GA_UCX_GETSERVBYNAME)(&par, &sent, par.s);
1645 if ((long)e == -1L)
1646 return NULL;
1647 if ((e & 1) == 0L) {
1648 C$$TRANSLATE(e);
1649 return NULL;
1650 }
1651 if ((s.sb.st[0] & 1) == 0) {
1652 C$$SOCK_TRANSLATE(&s.sb.st[0]);
1653 return NULL;
1654 }
1655 /*
1656 sent.s_port is supposed to be returned by UCX in network byte order.
1657 However, UCX 2.0 through 2.0C did not do this; 2.0D and later do it.
1658 But there is no way of knowing which UCX version, so we have a user-settable
1659 runtime variable. Note: UCX 2.0 was only for the VAX.
1660 */
1661 debug(F101,"UCX getservbyname port","",sent.s_port);
1662 debug(F101,"UCX getservbyname ntohs(port)","",ntohs(sent.s_port));
1663 if (ucx_port_bug) {
1664 sent.s_port = htons(sent.s_port);
1665 debug(F100,"UCX-PORT-BUG ON: swapping bytes","",0);
1666 debug(F101,"UCX swapped port","",sent.s_port);
1667 debug(F101,"UCX swapped ntohs(port)","",ntohs(sent.s_port));
1668 }
1669 return &sent;
1670 }
1671 #endif /* def OLDIP */
1672 #endif /* DEC_TCPIP */
1673 #endif /* EXCELAN */
1674
1675 int
gettcpport()1676 gettcpport() {
1677 return(svcnum);
1678 }
1679
1680 #endif /* TCPSOCKET */
1681
1682 #ifndef NOTCPOPTS
1683 #ifndef datageneral
1684 int
ck_linger(sock,onoff,timo)1685 ck_linger(sock, onoff, timo) int sock; int onoff; int timo; {
1686 /*
1687 The following, from William Bader, turns off the socket linger parameter,
1688 which makes a close() block until all data is sent. "I don't think that
1689 disabling linger can ever cause kermit to lose data, but you telnet to a
1690 flaky server (or to our modem server when the modem is in use), disabling
1691 linger prevents kermit from hanging on the close if you try to exit."
1692
1693 Modified by Jeff Altman to be generally useful.
1694 */
1695 #ifdef SOL_SOCKET
1696 #ifdef SO_LINGER
1697 struct linger set_linger_opt;
1698 struct linger get_linger_opt;
1699 SOCKOPT_T x;
1700
1701 #ifdef IKSD
1702 if (!inserver)
1703 #endif /* IKSD */
1704 if (sock == -1 ||
1705 nettype != NET_TCPA && nettype != NET_TCPB &&
1706 nettype != NET_SSH || ttmdm >= 0) {
1707 tcp_linger = onoff;
1708 tcp_linger_tmo = timo;
1709 return(1);
1710 }
1711 x = sizeof(get_linger_opt);
1712 if (getsockopt(sock, SOL_SOCKET, SO_LINGER,
1713 (char *)&get_linger_opt, &x)) {
1714 debug(F111,"TCP ck_linger can't get SO_LINGER",ck_errstr(),errno);
1715 } else if (x != sizeof(get_linger_opt)) {
1716 #ifdef OS2
1717 struct _linger16 {
1718 short s_linger;
1719 short s_onoff;
1720 } get_linger_opt16, set_linger_opt16;
1721 if ( x == sizeof(get_linger_opt16) ) {
1722 debug(F111,"TCP setlinger warning: SO_LINGER","len is 16-bit",x);
1723 if (getsockopt(sock,
1724 SOL_SOCKET, SO_LINGER,
1725 (char *)&get_linger_opt16, &x)
1726 ) {
1727 debug(F111,
1728 "TCP ck_linger can't get SO_LINGER",ck_errstr(),errno);
1729 } else if (get_linger_opt16.s_onoff != onoff ||
1730 get_linger_opt16.s_linger != timo)
1731 {
1732 set_linger_opt16.s_onoff = onoff;
1733 set_linger_opt16.s_linger = timo;
1734 if (setsockopt(sock,
1735 SOL_SOCKET,
1736 SO_LINGER,
1737 (char *)&set_linger_opt16,
1738 sizeof(set_linger_opt16))
1739 ) {
1740 debug(F111,
1741 "TCP ck_linger can't set SO_LINGER",
1742 ck_errstr(),
1743 errno
1744 );
1745 tcp_linger = get_linger_opt16.s_onoff;
1746 tcp_linger_tmo = get_linger_opt16.s_linger;
1747 } else {
1748 debug(F101,
1749 "TCP ck_linger new SO_LINGER","",
1750 set_linger_opt16.s_onoff);
1751 tcp_linger = set_linger_opt16.s_onoff;
1752 tcp_linger_tmo = set_linger_opt16.s_linger;
1753 return 1;
1754 }
1755 } else {
1756 debug(F101,"TCP ck_linger SO_LINGER unchanged","",
1757 get_linger_opt16.s_onoff);
1758 tcp_linger = get_linger_opt16.s_onoff;
1759 tcp_linger_tmo = get_linger_opt16.s_linger;
1760 return 1;
1761 }
1762 return(0);
1763 }
1764 #endif /* OS2 */
1765 debug(F111,"TCP ck_linger error: SO_LINGER","len",x);
1766 debug(F111,"TCP ck_linger SO_LINGER",
1767 "expected len",sizeof(get_linger_opt));
1768 debug(F111,"TCP ck_linger SO_LINGER","linger_opt.l_onoff",
1769 get_linger_opt.l_onoff);
1770 debug(F111,"TCP linger SO_LINGER","linger_opt.l_linger",
1771 get_linger_opt.l_linger);
1772 } else if (get_linger_opt.l_onoff != onoff ||
1773 get_linger_opt.l_linger != timo) {
1774 set_linger_opt.l_onoff = onoff;
1775 set_linger_opt.l_linger = timo;
1776 if (setsockopt(sock,
1777 SOL_SOCKET,
1778 SO_LINGER,
1779 (char *)&set_linger_opt,
1780 sizeof(set_linger_opt))) {
1781 debug(F111,"TCP ck_linger can't set SO_LINGER",ck_errstr(),errno);
1782 tcp_linger = get_linger_opt.l_onoff;
1783 tcp_linger_tmo = get_linger_opt.l_linger;
1784 } else {
1785 debug(F101,
1786 "TCP ck_linger new SO_LINGER",
1787 "",
1788 set_linger_opt.l_onoff
1789 );
1790 tcp_linger = set_linger_opt.l_onoff;
1791 tcp_linger_tmo = set_linger_opt.l_linger;
1792 return 1;
1793 }
1794 } else {
1795 debug(F101,"TCP ck_linger SO_LINGER unchanged","",
1796 get_linger_opt.l_onoff);
1797 tcp_linger = get_linger_opt.l_onoff;
1798 tcp_linger_tmo = get_linger_opt.l_linger;
1799 return 1;
1800 }
1801 #else
1802 debug(F100,"TCP ck_linger SO_LINGER not defined","",0);
1803 #endif /* SO_LINGER */
1804 #else
1805 debug(F100,"TCP ck_linger SO_SOCKET not defined","",0);
1806 #endif /* SOL_SOCKET */
1807 return(0);
1808 }
1809
1810 int
sendbuf(sock,size)1811 sendbuf(sock,size) int sock; int size; {
1812 /*
1813 The following, from William Bader, allows changing of socket buffer sizes,
1814 in case that might affect performance.
1815
1816 Modified by Jeff Altman to be generally useful.
1817 */
1818 #ifdef SOL_SOCKET
1819 #ifdef SO_SNDBUF
1820 int i, j;
1821 SOCKOPT_T x;
1822
1823 #ifdef IKSD
1824 if (!inserver)
1825 #endif /* IKSD */
1826 if (sock == -1 ||
1827 nettype != NET_TCPA && nettype != NET_TCPB && nettype != NET_SSH
1828 || ttmdm >= 0) {
1829 tcp_sendbuf = size;
1830 return 1;
1831 }
1832 x = sizeof(i);
1833 if (getsockopt(sock, SOL_SOCKET, SO_SNDBUF, (char *)&i, &x)) {
1834 debug(F111,"TCP sendbuf can't get SO_SNDBUF",ck_errstr(),errno);
1835 } else if (x != sizeof(i)) {
1836 #ifdef OS2
1837 short i16,j16;
1838 if (x == sizeof(i16)) {
1839 debug(F111,"TCP sendbuf warning: SO_SNDBUF","len is 16-bit",x);
1840 if (getsockopt(sock,
1841 SOL_SOCKET, SO_SNDBUF,
1842 (char *)&i16, &x)
1843 ) {
1844 debug(F111,"TCP sendbuf can't get SO_SNDBUF",
1845 ck_errstr(),errno);
1846 } else if (size <= 0) {
1847 tcp_sendbuf = i16;
1848 debug(F101,"TCP sendbuf SO_SNDBUF retrieved","",i16);
1849 return 1;
1850 } else if (i16 != size) {
1851 j16 = size;
1852 if (setsockopt(sock,
1853 SOL_SOCKET,
1854 SO_SNDBUF,
1855 (char *)&j16,
1856 sizeof(j16))
1857 ) {
1858 debug(F111,"TCP sendbuf can't set SO_SNDBUF",
1859 ck_errstr(),errno);
1860 } else {
1861 debug(F101,"TCP sendbuf old SO_SNDBUF","",i16);
1862 debug(F101,"TCP sendbuf new SO_SNDBUF","",j16);
1863 tcp_sendbuf = size;
1864 return 1;
1865 }
1866 } else {
1867 debug(F101,"TCP sendbuf SO_SNDBUF unchanged","",i16);
1868 tcp_sendbuf = size;
1869 return 1;
1870 }
1871 return(0);
1872 }
1873 #endif /* OS2 */
1874 debug(F111,"TCP sendbuf error: SO_SNDBUF","len",x);
1875 debug(F111,"TCP sendbuf SO_SNDBUF","expected len",sizeof(i));
1876 debug(F111,"TCP sendbuf SO_SNDBUF","i",i);
1877 } else if (size <= 0) {
1878 tcp_sendbuf = i;
1879 debug(F101,"TCP sendbuf SO_SNDBUF retrieved","",i);
1880 return 1;
1881 } else if (i != size) {
1882 j = size;
1883 if (setsockopt(sock, SOL_SOCKET, SO_SNDBUF, (char *)&j, sizeof(j))) {
1884 debug(F111,"TCP sendbuf can't set SO_SNDBUF",ck_errstr(),errno);
1885 tcp_sendbuf = i;
1886 } else {
1887 debug(F101,"TCP sendbuf old SO_SNDBUF","",i);
1888 debug(F101,"TCP sendbuf new SO_SNDBUF","",j);
1889 tcp_sendbuf = size;
1890 return 1;
1891 }
1892 } else {
1893 debug(F101,"TCP sendbuf SO_SNDBUF unchanged","",i);
1894 tcp_sendbuf = size;
1895 return 1;
1896 }
1897 #else
1898 debug(F100,"TCP sendbuf SO_SNDBUF not defined","",0);
1899 #endif /* SO_SNDBUF */
1900 #else
1901 debug(F100,"TCP sendbuf SO_SOCKET not defined","",0);
1902 #endif /* SOL_SOCKET */
1903 return(0);
1904 }
1905
1906 int
recvbuf(sock,size)1907 recvbuf(sock,size) int sock; int size; {
1908 /*
1909 The following, from William Bader, allows changing of socket buffer sizes,
1910 in case that might affect performance.
1911
1912 Modified by Jeff Altman to be generally useful.
1913 */
1914 #ifdef SOL_SOCKET
1915 #ifdef SO_RCVBUF
1916 int i, j;
1917 SOCKOPT_T x;
1918
1919 #ifdef IKSD
1920 if (!inserver)
1921 #endif /* IKSD */
1922 if (sock == -1 ||
1923 nettype != NET_TCPA && nettype != NET_TCPB &&
1924 nettype != NET_SSH || ttmdm >= 0) {
1925 tcp_recvbuf = size;
1926 return(1);
1927 }
1928 x = sizeof(i);
1929 if (getsockopt(sock, SOL_SOCKET, SO_RCVBUF, (char *)&i, &x)) {
1930 debug(F111,"TCP recvbuf can't get SO_RCVBUF",ck_errstr(),errno);
1931 } else if (x != sizeof(i)) {
1932 #ifdef OS2
1933 short i16,j16;
1934 if ( x == sizeof(i16) ) {
1935 debug(F111,"TCP recvbuf warning: SO_RCVBUF","len is 16-bit",x);
1936 if (getsockopt(sock,
1937 SOL_SOCKET, SO_RCVBUF,
1938 (char *)&i16, &x)
1939 ) {
1940 debug(F111,"TCP recvbuf can't get SO_RCVBUF",
1941 ck_errstr(),errno);
1942 } else if (size <= 0) {
1943 tcp_recvbuf = i16;
1944 debug(F101,"TCP recvbuf SO_RCVBUF retrieved","",i16);
1945 return 1;
1946 } else if (i16 != size) {
1947 j16 = size;
1948 if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF, (char *)&j16,
1949 sizeof(j16))) {
1950 debug(F111,"TCP recvbuf can' set SO_RCVBUF",
1951 ck_errstr(),errno);
1952 } else {
1953 debug(F101,"TCP recvbuf old SO_RCVBUF","",i16);
1954 debug(F101,"TCP recvbuf new SO_RCVBUF","",j16);
1955 tcp_recvbuf = size;
1956 return 1;
1957 }
1958 } else {
1959 debug(F101,"TCP recvbuf SO_RCVBUF unchanged","",i16);
1960 tcp_recvbuf = size;
1961 return 1;
1962 }
1963 return(0);
1964 }
1965 #endif /* OS2 */
1966 debug(F111,"TCP recvbuf error: SO_RCVBUF","len",x);
1967 debug(F111,"TCP recvbuf SO_RCVBUF","expected len",sizeof(i));
1968 debug(F111,"TCP recvbuf SO_RCVBUF","i",i);
1969 } else if (size <= 0) {
1970 tcp_recvbuf = i;
1971 debug(F101,"TCP recvbuf SO_RCVBUF retrieved","",i);
1972 return 1;
1973 } else if (i != size) {
1974 j = size;
1975 if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF, (char *)&j, sizeof(j))) {
1976 debug(F111,"TCP recvbuf can't set SO_RCVBUF",ck_errstr(),errno);
1977 tcp_recvbuf = i;
1978 } else {
1979 debug(F101,"TCP recvbuf old SO_RCVBUF","",i);
1980 debug(F101,"TCP recvbuf new SO_RCVBUF","",j);
1981 tcp_recvbuf = size;
1982 return 1;
1983 }
1984 } else {
1985 debug(F101,"TCP recvbuf SO_RCVBUF unchanged","",i);
1986 tcp_recvbuf = size;
1987 return 1;
1988 }
1989 #else
1990 debug(F100,"TCP recvbuf SO_RCVBUF not defined","",0);
1991 #endif /* SO_RCVBUF */
1992 #else
1993 debug(F100,"TCP recvbuf SO_SOCKET not defined","",0);
1994 #endif /* SOL_SOCKET */
1995 return 0;
1996 }
1997
1998 int
keepalive(sock,onoff)1999 keepalive(sock,onoff) int sock; int onoff; {
2000 #ifdef SOL_SOCKET
2001 #ifdef SO_KEEPALIVE
2002 int get_keepalive_opt;
2003 int set_keepalive_opt;
2004 SOCKOPT_T x;
2005
2006 debug(F111,"TCP keepalive","sock",sock);
2007 debug(F111,"TCP keepalive","nettype",nettype);
2008 debug(F111,"TCP keepalive","ttmdm",ttmdm);
2009
2010 #ifdef IKSD
2011 if (!inserver)
2012 #endif /* IKSD */
2013 if (sock == -1 ||
2014 nettype != NET_TCPA && nettype != NET_TCPB && nettype != NET_SSH
2015 || ttmdm >= 0) {
2016 tcp_keepalive = onoff;
2017 return 1;
2018 }
2019 x = sizeof(get_keepalive_opt);
2020 if (getsockopt(sock,
2021 SOL_SOCKET, SO_KEEPALIVE, (char *)&get_keepalive_opt, &x)) {
2022 debug(F111,"TCP keepalive can't get SO_KEEPALIVE",ck_errstr(),errno);
2023 } else if (x != sizeof(get_keepalive_opt)) {
2024 #ifdef OS2
2025 short get_keepalive_opt16;
2026 short set_keepalive_opt16;
2027 if (x == sizeof(get_keepalive_opt16)) {
2028 debug(F111,"TCP keepalive warning: SO_KEEPALIVE",
2029 "len is 16-bit",x);
2030 if (getsockopt(sock,
2031 SOL_SOCKET, SO_KEEPALIVE,
2032 (char *)&get_keepalive_opt16, &x)
2033 ) {
2034 debug(F111,
2035 "TCP keepalive can't get SO_KEEPALIVE",
2036 ck_errstr(),
2037 errno
2038 );
2039 } else if (get_keepalive_opt16 != onoff) {
2040 set_keepalive_opt16 = onoff;
2041 if (setsockopt(sock,
2042 SOL_SOCKET,
2043 SO_KEEPALIVE,
2044 (char *)&set_keepalive_opt16,
2045 sizeof(set_keepalive_opt16))
2046 ) {
2047 debug(F111,
2048 "TCP keepalive can't clear SO_KEEPALIVE",
2049 ck_errstr(),
2050 errno
2051 );
2052 tcp_keepalive = get_keepalive_opt16;
2053 } else {
2054 debug(F101,
2055 "TCP keepalive new SO_KEEPALIVE","",
2056 set_keepalive_opt16);
2057 tcp_keepalive = set_keepalive_opt16;
2058 return 1;
2059 }
2060 } else {
2061 debug(F101,"TCP keepalive SO_KEEPALIVE unchanged","",
2062 get_keepalive_opt16);
2063 tcp_keepalive = onoff;
2064 return 1;
2065 }
2066 return(0);
2067 }
2068 #endif /* OS2 */
2069 debug(F111,"TCP keepalive error: SO_KEEPALIVE","len",x);
2070 debug(F111,
2071 "TCP keepalive SO_KEEPALIVE",
2072 "expected len",
2073 sizeof(get_keepalive_opt)
2074 );
2075 debug(F111,
2076 "TCP keepalive SO_KEEPALIVE",
2077 "keepalive_opt",
2078 get_keepalive_opt
2079 );
2080 } else if (get_keepalive_opt != onoff) {
2081 set_keepalive_opt = onoff;
2082 if (setsockopt(sock,
2083 SOL_SOCKET,
2084 SO_KEEPALIVE,
2085 (char *)&set_keepalive_opt,
2086 sizeof(set_keepalive_opt))
2087 ) {
2088 debug(F111,
2089 "TCP keepalive can't clear SO_KEEPALIVE",
2090 ck_errstr(),
2091 errno
2092 );
2093 tcp_keepalive = get_keepalive_opt;
2094 } else {
2095 debug(F101,
2096 "TCP keepalive new SO_KEEPALIVE",
2097 "",
2098 set_keepalive_opt
2099 );
2100 tcp_keepalive = onoff;
2101 return 1;
2102 }
2103 } else {
2104 debug(F101,"TCP keepalive SO_KEEPALIVE unchanged",
2105 "",
2106 get_keepalive_opt
2107 );
2108 tcp_keepalive = onoff;
2109 return 1;
2110 }
2111 #else
2112 debug(F100,"TCP keepalive SO_KEEPALIVE not defined","",0);
2113 #endif /* SO_KEEPALIVE */
2114 #else
2115 debug(F100,"TCP keepalive SO_SOCKET not defined","",0);
2116 #endif /* SOL_SOCKET */
2117 return(0);
2118 }
2119
2120 int
dontroute(sock,onoff)2121 dontroute(sock,onoff) int sock; int onoff; {
2122 #ifdef SOL_SOCKET
2123 #ifdef SO_DONTROUTE
2124 int get_dontroute_opt;
2125 int set_dontroute_opt;
2126 SOCKOPT_T x;
2127
2128 #ifdef IKSD
2129 if (!inserver)
2130 #endif /* IKSD */
2131 if (sock == -1 ||
2132 nettype != NET_TCPA && nettype != NET_TCPB && nettype != NET_SSH
2133 || ttmdm >= 0) {
2134 tcp_dontroute = onoff;
2135 return 1;
2136 }
2137 x = sizeof(get_dontroute_opt);
2138 if (getsockopt(sock,
2139 SOL_SOCKET, SO_DONTROUTE, (char *)&get_dontroute_opt, &x)) {
2140 debug(F111,"TCP dontroute can't get SO_DONTROUTE",ck_errstr(),errno);
2141 } else if (x != sizeof(get_dontroute_opt)) {
2142 #ifdef OS2
2143 short get_dontroute_opt16;
2144 short set_dontroute_opt16;
2145 if (x == sizeof(get_dontroute_opt16)) {
2146 debug(F111,"TCP dontroute warning: SO_DONTROUTE",
2147 "len is 16-bit",x);
2148 if (getsockopt(sock,
2149 SOL_SOCKET, SO_DONTROUTE,
2150 (char *)&get_dontroute_opt16, &x)
2151 ) {
2152 debug(F111,
2153 "TCP dontroute can't get SO_DONTROUTE",
2154 ck_errstr(),
2155 errno
2156 );
2157 } else if (get_dontroute_opt16 != onoff) {
2158 set_dontroute_opt16 = onoff;
2159 if (setsockopt(sock,
2160 SOL_SOCKET,
2161 SO_DONTROUTE,
2162 (char *)&set_dontroute_opt16,
2163 sizeof(set_dontroute_opt16))
2164 ) {
2165 debug(F111,
2166 "TCP dontroute can't clear SO_DONTROUTE",
2167 ck_errstr(),
2168 errno
2169 );
2170 tcp_dontroute = get_dontroute_opt16;
2171 } else {
2172 debug(F101,
2173 "TCP dontroute new SO_DONTROUTE","",
2174 set_dontroute_opt16);
2175 tcp_dontroute = set_dontroute_opt16;
2176 return 1;
2177 }
2178 } else {
2179 debug(F101,"TCP dontroute SO_DONTROUTE unchanged","",
2180 get_dontroute_opt16);
2181 tcp_dontroute = onoff;
2182 return 1;
2183 }
2184 return(0);
2185 }
2186 #endif /* OS2 */
2187 debug(F111,"TCP dontroute error: SO_DONTROUTE","len",x);
2188 debug(F111,
2189 "TCP dontroute SO_DONTROUTE",
2190 "expected len",
2191 sizeof(get_dontroute_opt)
2192 );
2193 debug(F111,
2194 "TCP dontroute SO_DONTROUTE",
2195 "dontroute_opt",
2196 get_dontroute_opt
2197 );
2198 } else if (get_dontroute_opt != onoff) {
2199 set_dontroute_opt = onoff;
2200 if (setsockopt(sock,
2201 SOL_SOCKET,
2202 SO_DONTROUTE,
2203 (char *)&set_dontroute_opt,
2204 sizeof(set_dontroute_opt))
2205 ) {
2206 debug(F111,
2207 "TCP dontroute can't clear SO_DONTROUTE",
2208 ck_errstr(),
2209 errno
2210 );
2211 tcp_dontroute = get_dontroute_opt;
2212 } else {
2213 debug(F101,
2214 "TCP dontroute new SO_DONTROUTE",
2215 "",
2216 set_dontroute_opt
2217 );
2218 tcp_dontroute = onoff;
2219 return 1;
2220 }
2221 } else {
2222 debug(F101,"TCP dontroute SO_DONTROUTE unchanged",
2223 "",
2224 get_dontroute_opt
2225 );
2226 tcp_dontroute = onoff;
2227 return 1;
2228 }
2229 #else
2230 debug(F100,"TCP dontroute SO_DONTROUTE not defined","",0);
2231 #endif /* SO_DONTROUTE */
2232 #else
2233 debug(F100,"TCP dontroute SO_SOCKET not defined","",0);
2234 #endif /* SOL_SOCKET */
2235 return(0);
2236 }
2237
2238 int
no_delay(sock,onoff)2239 no_delay(sock,onoff) int sock; int onoff; {
2240 #ifdef SOL_SOCKET
2241 #ifdef TCP_NODELAY
2242 int get_nodelay_opt;
2243 int set_nodelay_opt;
2244 SOCKOPT_T x;
2245
2246 #ifdef IKSD
2247 if (!inserver)
2248 #endif /* IKSD */
2249 if (sock == -1 ||
2250 nettype != NET_TCPA && nettype != NET_TCPB && nettype != NET_SSH
2251 || ttmdm >= 0) {
2252 tcp_nodelay = onoff;
2253 return(1);
2254 }
2255 x = sizeof(get_nodelay_opt);
2256 if (getsockopt(sock,IPPROTO_TCP,TCP_NODELAY,
2257 (char *)&get_nodelay_opt,&x)) {
2258 debug(F111,
2259 "TCP no_delay can't get TCP_NODELAY",
2260 ck_errstr(),
2261 errno);
2262 } else if (x != sizeof(get_nodelay_opt)) {
2263 #ifdef OS2
2264 short get_nodelay_opt16;
2265 short set_nodelay_opt16;
2266 if (x == sizeof(get_nodelay_opt16)) {
2267 debug(F111,"TCP no_delay warning: TCP_NODELAY","len is 16-bit",x);
2268 if (getsockopt(sock,
2269 IPPROTO_TCP, TCP_NODELAY,
2270 (char *)&get_nodelay_opt16, &x)
2271 ) {
2272 debug(F111,
2273 "TCP no_delay can't get TCP_NODELAY",
2274 ck_errstr(),
2275 errno);
2276 } else if (get_nodelay_opt16 != onoff) {
2277 set_nodelay_opt16 = onoff;
2278 if (setsockopt(sock,
2279 IPPROTO_TCP,
2280 TCP_NODELAY,
2281 (char *)&set_nodelay_opt16,
2282 sizeof(set_nodelay_opt16))
2283 ) {
2284 debug(F111,
2285 "TCP no_delay can't clear TCP_NODELAY",
2286 ck_errstr(),
2287 errno);
2288 tcp_nodelay = get_nodelay_opt16;
2289 } else {
2290 debug(F101,
2291 "TCP no_delay new TCP_NODELAY",
2292 "",
2293 set_nodelay_opt16);
2294 tcp_nodelay = onoff;
2295 return 1;
2296 }
2297 } else {
2298 debug(F101,"TCP no_delay TCP_NODELAY unchanged","",
2299 get_nodelay_opt16);
2300 tcp_nodelay = onoff;
2301 return 1;
2302 }
2303 return(0);
2304 }
2305 #endif /* OS2 */
2306 debug(F111,"TCP no_delay error: TCP_NODELAY","len",x);
2307 debug(F111,"TCP no_delay TCP_NODELAY","expected len",
2308 sizeof(get_nodelay_opt));
2309 debug(F111,"TCP no_delay TCP_NODELAY","nodelay_opt",get_nodelay_opt);
2310 } else if (get_nodelay_opt != onoff) {
2311 set_nodelay_opt = onoff;
2312 if (setsockopt(sock,
2313 IPPROTO_TCP,
2314 TCP_NODELAY,
2315 (char *)&set_nodelay_opt,
2316 sizeof(set_nodelay_opt))) {
2317 debug(F111,
2318 "TCP no_delay can't clear TCP_NODELAY",
2319 ck_errstr(),
2320 errno
2321 );
2322 tcp_nodelay = get_nodelay_opt;
2323 } else {
2324 debug(F101,"TCP no_delay new TCP_NODELAY","",set_nodelay_opt);
2325 tcp_nodelay = onoff;
2326 return 1;
2327 }
2328 } else {
2329 debug(F101,"TCP no_delay TCP_NODELAY unchanged","",get_nodelay_opt);
2330 tcp_nodelay = onoff;
2331 return(1);
2332 }
2333 #else
2334 debug(F100,"TCP no_delay TCP_NODELAY not defined","",0);
2335 #endif /* TCP_NODELAY */
2336 #else
2337 debug(F100,"TCP no_delay SO_SOCKET not defined","",0);
2338 #endif /* SOL_SOCKET */
2339 return 0;
2340 }
2341 #endif /* datageneral */
2342 #endif /* NOTCPOPTS */
2343
2344 #ifdef SUNX25
2345 #ifndef X25_WR_FACILITY
2346 /* For Solaris 2.3 / SunLink 8.x - see comments in ckcnet.h */
2347 void
bzero(s,n)2348 bzero(s,n) char *s; int n; {
2349 memset(s,0,n);
2350 }
2351 #endif /* X25_WR_FACILITY */
2352 #endif /* SUNX25 */
2353
2354 #ifdef TCPSOCKET
2355 #ifndef OS2
2356 #ifndef NOLISTEN
2357
2358 #ifdef BSDSELECT
2359 #ifndef VMS
2360 #ifndef BELLV10
2361 #ifndef datageneral
2362 #ifdef hp9000s500 /* HP-9000/500 HP-U 5.21 */
2363 #include <time.h>
2364 #else
2365
2366 /****** THIS SECTION ADDED BY STEVE RANCE - OS9 NETWORK SERVER
2367 * ------------------------------------------------------
2368 *
2369 * Due to OS9's Lack of a select() call, the following seems to be
2370 * enough to fool the rest of the code into compiling. The only
2371 * effect that I can see is using control L to refresh the status
2372 * display gets qued up until some network packets arrive.
2373 *
2374 * This solution is by no means elegant but works enough to be
2375 * a (the) solution.
2376 *
2377 * Also with the defines I had specified in my makefile I had to
2378 * have an #endif right at the end of the file when compiling.
2379 * I did not bother speding time to find out why.
2380 *
2381 * COPTS = -to=osk -d=OSK -d=TCPSOCKET -d=SELECT -d=VOID=void -d=SIG_V \
2382 * -d=DYNAMIC -d=PARSENSE -d=KANJI -d=MYCURSES -d=ZFCDAT \
2383 * -d=CK_APC -d=CK_REDIR -d=RENAME -d=CK_TTYFD -d=NOOLDMODEMS \
2384 * -d=CK_ANSIC -d=CK_XYZ -tp=68040d -l=netdb.l -l=socklib.l \
2385 * -l=termlib.l -l=math.l -l=sys_clib.l
2386 *
2387 * stever@ozemail.com.au
2388 */
2389
2390 #ifdef OSK
2391 #define BSDSELECT /* switch on BSD select code */
2392 #define FD_SETSIZE 32 /* Max # of paths in OS9 */
2393 #define FD_ZERO(p) ((*p)=0)
2394 #define FD_SET(n,b) ((*b)|=(1<<(n)))
2395 #define FD_ISSET(n,b) 1 /* always say data is ready */
2396 #define select(a,b,c,d,e) 1 /* always say 1 path has data */
2397 typedef int fd_set; /* keep BSD Code Happy */
2398 struct timeval {int tv_sec,tv_usec;}; /* keep BSD Code Happy */
2399
2400 /****** END OF OS9 MODS FROM STEVE RANCE **************************/
2401 #endif /* OSK */
2402
2403 #include <sys/time.h>
2404 #endif /* hp9000s500 */
2405 #endif /* datageneral */
2406 #endif /* BELLV10 */
2407 #endif /* VMS */
2408 #ifdef SELECT_H
2409 #include <sys/select.h>
2410 #endif /* SELECT_H */
2411 #endif /* BSDSELECT */
2412
2413 #ifdef SELECT
2414 #ifdef CK_SCOV5
2415 #include <sys/select.h>
2416 #endif /* CK_SCOV5 */
2417 #endif /* SELECT */
2418
2419 #ifdef NOTUSED
2420 /* T C P S O C K E T _ O P E N -- Open a preexisting socket number */
2421
2422 int
tcpsocket_open(name,lcl,nett,timo)2423 tcpsocket_open(name,lcl,nett,timo) char * name; int * lcl; int nett; int timo {
2424 int on = 1;
2425 static struct servent *service, servrec;
2426 static struct hostent *host;
2427 static struct sockaddr_in saddr;
2428 static
2429 #ifdef UCX50
2430 unsigned
2431 #endif /* UCX50 */
2432 int saddrlen;
2433 #ifdef BSDSELECT
2434 fd_set rfds;
2435 struct timeval tv;
2436 #else
2437 #ifdef BELLSELECT
2438 fd_set rfds;
2439 #else
2440 fd_set rfds;
2441 fd_set rfds;
2442 struct timeval {
2443 long tv_sec;
2444 long tv_usec;
2445 } tv;
2446 #endif /* BELLSELECT */
2447 #endif /* BSDSELECT */
2448
2449 debug(F101,"tcpsocket_open nett","",nett);
2450 *ipaddr = '\0';
2451
2452 if (nett != NET_TCPB)
2453 return(-1); /* BSD socket support */
2454
2455 netclos(); /* Close any previous connection. */
2456 ckstrncpy(namecopy, name, NAMECPYL); /* Copy the hostname. */
2457 #ifdef COMMENT
2458 /* Jeff's version from 30 Dec 2005 doesn't inhibit Telnet */
2459 if (ttnproto != NP_TCPRAW &&
2460 ttnproto != NP_SSL_RAW &&
2461 ttnproto != NP_TLS_RAW)
2462 ttnproto = NP_NONE; /* No protocol selected yet. */
2463 #else
2464 /* fdc's version from 4 Dec 2005 works ok */
2465 if (ttnproto != NP_TCPRAW)
2466 ttnproto = NP_NONE; /* No protocol selected yet. */
2467 #endif /* COMMENT */
2468 debug(F110,"tcpsocket_open namecopy",namecopy,0);
2469
2470 /* Assign the socket number to ttyfd and then fill in tcp structures */
2471 ttyfd = atoi(&name[1]);
2472 debug(F111,"tcpsocket_open","ttyfd",ttyfd);
2473
2474 #ifndef NOTCPOPTS
2475 #ifdef SOL_SOCKET
2476 setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
2477
2478 #ifndef datageneral
2479 #ifdef TCP_NODELAY
2480 no_delay(ttyfd,tcp_nodelay);
2481 #endif /* TCP_NODELAY */
2482 #ifdef SO_KEEPALIVE
2483 keepalive(ttyfd,tcp_keepalive);
2484 #endif /* SO_KEEPALIVE */
2485 #ifdef SO_LINGER
2486 ck_linger(ttyfd,tcp_linger, tcp_linger_tmo);
2487 #endif /* SO_LINGER */
2488 #ifdef SO_SNDBUF
2489 sendbuf(ttyfd,tcp_sendbuf);
2490 #endif /* SO_SNDBUF */
2491 #ifdef SO_RCVBUF
2492 recvbuf(ttyfd,tcp_recvbuf);
2493 #endif /* SO_RCVBUF */
2494 #endif /* datageneral */
2495 #endif /* SOL_SOCKET */
2496 #endif /* NOTCPOPTS */
2497
2498 #ifdef NT_TCP_OVERLAPPED
2499 OverlappedWriteInit();
2500 OverlappedReadInit();
2501 #endif /* NT_TCP_OVERLAPPED */
2502
2503
2504 /* Get the name of the host we are connected to */
2505
2506 saddrlen = sizeof(saddr);
2507 getpeername(ttyfd,(struct sockaddr *)&saddr,&saddrlen);
2508
2509 ckstrncpy(ipaddr,(char *)inet_ntoa(saddr.sin_addr),20);
2510
2511 if (tcp_rdns == SET_ON
2512 #ifdef CK_KERBEROS
2513 || tcp_rdns == SET_AUTO &&
2514 (ck_krb5_is_installed() || ck_krb4_is_installed())
2515 #endif /* CK_KERBEROS */
2516 #ifndef NOHTTP
2517 && (tcp_http_proxy == NULL)
2518 #endif /* NOHTTP */
2519 #ifdef CK_SSL
2520 && !(ssl_only_flag || tls_only_flag)
2521 #endif /* CK_SSL */
2522 ) { /* Reverse DNS */
2523 if (!quiet) {
2524 printf(" Reverse DNS Lookup... ");
2525 fflush(stdout);
2526 }
2527 host = gethostbyaddr((char *)&saddr.sin_addr,4,PF_INET);
2528 debug(F110,"tcpsocket_open gethostbyaddr",host ? "OK" : "FAILED",0);
2529 if (host) {
2530 host = ck_copyhostent(host);
2531 debug(F100,"tcpsocket_open gethostbyaddr != NULL","",0);
2532 if (!quiet) {
2533 printf("(OK)\n");
2534 fflush(stdout);
2535 }
2536 ckstrncpy(name, host->h_name, 80);
2537 ckstrncat(name, ":", 80);
2538 ckstrncat(name,ckuitoa(ntohs(saddr.sin_port)), 80);
2539 if (!quiet
2540 #ifndef NOICP
2541 && !doconx
2542 #endif /* NOICP */
2543 )
2544 printf("%s connected on port %d\n",
2545 host->h_name,
2546 ntohs(saddr.sin_port)
2547 );
2548 } else if (!quiet)
2549 printf("Failed\n");
2550 } else if (!quiet)
2551 printf("(OK)\n");
2552
2553 if (tcp_rdns != SET_ON || !host) {
2554 ckstrncpy(name,ipaddr,80);
2555 ckstrncat(name,":",80);
2556 ckstrncat(name,ckuitoa(ntohs(saddr.sin_port)),80);
2557 if (!quiet
2558 #ifdef NOICP
2559 && !doconx
2560 #endif /* NOICP */
2561 )
2562 printf("%s connected on port %d\n",ipaddr,ntohs(saddr.sin_port));
2563 }
2564 if (!quiet) fflush(stdout);
2565 ttnet = nett; /* TCP/IP (sockets) network */
2566
2567 #ifdef RLOGCODE
2568 if (ntohs(saddr.sin_port) == 513)
2569 ttnproto = NP_LOGIN;
2570 else
2571 #endif /* RLOGCODE */
2572 /* Assume the service is TELNET. */
2573 #ifdef COMMENT
2574 /* Jeff's code from 2005/12/30 */
2575 if (ttnproto != NP_TCP_RAW &&
2576 ttnproto != NP_SSL_RAW &&
2577 ttnproto != NP_TLS_RAW)
2578 #else
2579 /* fdc's code from 2005/12/04 */
2580 if (ttnproto != NP_TCPRAW)
2581 #endif /* COMMENT */
2582 ttnproto = NP_TELNET; /* Yes, set global flag. */
2583 #ifdef CK_SECURITY
2584 /* Before Initialization Telnet/Rlogin Negotiations Init Kerberos */
2585 ck_auth_init((tcp_rdns && host && host->h_name && host->h_name[0]) ?
2586 host->h_name : ipaddr,
2587 ipaddr,
2588 uidbuf,
2589 ttyfd
2590 );
2591 #endif /* CK_SECURITY */
2592 if (tn_ini() < 0) /* Start/Reset TELNET negotiations */
2593 if (ttchk() < 0) /* Did it fail due to connect loss? */
2594 return(-1);
2595
2596 if (*lcl < 0) *lcl = 1; /* Local mode. */
2597
2598 return(0); /* Done. */
2599 }
2600 #endif /* NOTUSED */
2601
2602 /* T C P S R V _ O P E N -- Open a TCP/IP Server connection */
2603 /*
2604 Calling conventions same as ttopen(), except third argument is network
2605 type rather than modem type.
2606 */
2607 int
tcpsrv_open(name,lcl,nett,timo)2608 tcpsrv_open(name,lcl,nett,timo) char * name; int * lcl; int nett; int timo; {
2609 char *p;
2610 int i, x;
2611 SOCKOPT_T on = 1;
2612 int ready_to_accept = 0;
2613 static struct servent *service, *service2, servrec;
2614 static struct hostent *host;
2615 static struct sockaddr_in saddr;
2616 struct sockaddr_in l_addr;
2617 GSOCKNAME_T l_slen;
2618 #ifdef UCX50
2619 static u_int saddrlen;
2620 #else
2621 static SOCKOPT_T saddrlen;
2622 #endif /* UCX50 */
2623
2624 #ifdef BSDSELECT
2625 fd_set rfds;
2626 struct timeval tv;
2627 #else
2628 #ifdef BELLSELCT
2629 fd_set rfds;
2630 #else
2631 fd_set rfds;
2632 struct timeval {
2633 long tv_sec;
2634 long tv_usec;
2635 } tv;
2636 #endif /* BELLSELECT */
2637 #endif /* BSDSELECT */
2638 #ifdef CK_SSL
2639 int ssl_failed = 0;
2640 #endif /* CK_SSL */
2641
2642 debug(F101,"tcpsrv_open nett","",nett);
2643 *ipaddr = '\0';
2644
2645 if (nett != NET_TCPB)
2646 return(-1); /* BSD socket support */
2647
2648 netclos(); /* Close any previous connection. */
2649 ckstrncpy(namecopy, name, NAMECPYL); /* Copy the hostname. */
2650 /* Don't do this. */
2651 #ifdef COMMENT
2652 /* fdc */
2653 if (ttnproto != NP_TCPRAW)
2654 ttnproto = NP_NONE; /* No protocol selected yet. */
2655 #endif /* COMMENT */
2656 #ifdef COMMENT
2657 /* Jeff */
2658 if (ttnproto != NP_TCP_RAW &&
2659 ttnproto != NP_SSL_RAW &&
2660 ttnproto != NP_TLS_RAW)
2661 ttnproto = NP_NONE; /* No protocol selected yet. */
2662 #endif /* COMMENT */
2663 debug(F110,"tcpsrv_open namecopy",namecopy,0);
2664
2665 p = namecopy; /* Was a service requested? */
2666 while (*p != '\0' && *p != ':')
2667 p++; /* Look for colon */
2668 if (*p == ':') { /* Have a colon */
2669 *p++ = '\0'; /* Get service name or number */
2670 } else { /* Otherwise use kermit */
2671 p = "kermit";
2672 }
2673 debug(F110,"tcpsrv_open service requested",p,0);
2674 if (isdigit(*p)) { /* Use socket number without lookup */
2675 service = &servrec;
2676 service->s_port = htons((unsigned short)atoi(p));
2677 } else { /* Otherwise lookup the service name */
2678 service = getservbyname(p, "tcp");
2679 }
2680 if (!service && !strcmp("kermit",p)) { /* Use Kermit service port */
2681 service = &servrec;
2682 service->s_port = htons(1649);
2683 }
2684 #ifdef RLOGCODE
2685 if (service && !strcmp("login",p) && service->s_port != htons(513)) {
2686 fprintf(stderr,
2687 " Warning: login service on port %d instead of port 513\n",
2688 ntohs(service->s_port));
2689 fprintf(stderr, " Edit SERVICES file if RLOGIN fails to connect.\n");
2690 debug(F101,"tcpsrv_open login on port","",ntohs(service->s_port));
2691 }
2692 #endif /* RLOGCODE */
2693 if (!service) {
2694 fprintf(stderr, "Cannot find port for service: %s\n", p);
2695 debug(F111,"tcpsrv_open can't get service",p,errno);
2696 errno = 0; /* rather than mislead */
2697 return(-1);
2698 }
2699
2700 /* If we currently have a listen active but port has changed then close */
2701
2702 debug(F101,"tcpsrv_open checking previous connection","",tcpsrfd);
2703 debug(F101,"tcpsrv_open previous tcpsrv_port","",tcpsrv_port);
2704 if (tcpsrfd != -1 &&
2705 tcpsrv_port != ntohs((unsigned short)service->s_port)) {
2706 debug(F100,"tcpsrv_open closing previous connection","",0);
2707 #ifdef TCPIPLIB
2708 socket_close(tcpsrfd);
2709 #else
2710 close(tcpsrfd);
2711 #endif /* TCPIPLIB */
2712 tcpsrfd = -1;
2713 }
2714 debug(F100,"tcpsrv_open tcpsrfd","",tcpsrfd);
2715 if (tcpsrfd == -1) {
2716
2717 /* Set up socket structure and get host address */
2718
2719 bzero((char *)&saddr, sizeof(saddr));
2720 debug(F100,"tcpsrv_open bzero ok","",0);
2721 saddr.sin_family = AF_INET;
2722 if (tcp_address) {
2723 #ifdef INADDRX
2724 inaddrx = inet_addr(tcp_address);
2725 saddr.sin_addr.s_addr = *(unsigned long *)&inaddrx;
2726 #else
2727 saddr.sin_addr.s_addr = inet_addr(tcp_address);
2728 #endif /* INADDRX */
2729 } else
2730 saddr.sin_addr.s_addr = INADDR_ANY;
2731
2732 /* Get a file descriptor for the connection. */
2733
2734 saddr.sin_port = service->s_port;
2735 ipaddr[0] = '\0';
2736
2737 debug(F100,"tcpsrv_open calling socket","",0);
2738 if ((tcpsrfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
2739 perror("TCP socket error");
2740 debug(F101,"tcpsrv_open socket error","",errno);
2741 return (-1);
2742 }
2743 errno = 0;
2744
2745 /* Specify the Port may be reused */
2746
2747 debug(F100,"tcpsrv_open calling setsockopt","",0);
2748 x = setsockopt(tcpsrfd,
2749 SOL_SOCKET,SO_REUSEADDR,(char *)&on,sizeof on);
2750 debug(F101,"tcpsrv_open setsockopt","",x);
2751
2752 /* Now bind to the socket */
2753 printf("\nBinding socket to port %d ...\n",
2754 ntohs((unsigned short)service->s_port));
2755 if (bind(tcpsrfd, (struct sockaddr *)&saddr, sizeof(saddr)) < 0) {
2756 i = errno; /* Save error code */
2757 #ifdef TCPIPLIB
2758 socket_close(tcpsrfd);
2759 #else /* TCPIPLIB */
2760 close(tcpsrfd);
2761 #endif /* TCPIPLIB */
2762 tcpsrfd = -1;
2763 tcpsrv_port = 0;
2764 ttyfd = -1;
2765 wasclosed = 1;
2766 errno = i; /* and report this error */
2767 debug(F101,"tcpsrv_open bind errno","",errno);
2768 printf("?Unable to bind to socket (errno = %d)\n",errno);
2769 return(-1);
2770 }
2771 debug(F100,"tcpsrv_open bind OK","",0);
2772 printf("Listening ...\n");
2773 if (listen(tcpsrfd, 15) < 0) {
2774 i = errno; /* Save error code */
2775 #ifdef TCPIPLIB
2776 socket_close(tcpsrfd);
2777 #else /* TCPIPLIB */
2778 close(tcpsrfd);
2779 #endif /* TCPIPLIB */
2780 tcpsrfd = -1;
2781 tcpsrv_port = 0;
2782 ttyfd = -1;
2783 wasclosed = 1;
2784 errno = i; /* And report this error */
2785 debug(F101,"tcpsrv_open listen errno","",errno);
2786 return(-1);
2787 }
2788 debug(F100,"tcpsrv_open listen OK","",0);
2789 tcpsrv_port = ntohs((unsigned short)service->s_port);
2790 }
2791
2792 #ifdef CK_SSL
2793 if (ck_ssleay_is_installed()) {
2794 if (!ssl_tn_init(SSL_SERVER)) {
2795 ssl_failed = 1;
2796 if (bio_err!=NULL) {
2797 BIO_printf(bio_err,"do_ssleay_init() failed\n");
2798 ERR_print_errors(bio_err);
2799 } else {
2800 fflush(stderr);
2801 fprintf(stderr,"do_ssleay_init() failed\n");
2802 ERR_print_errors_fp(stderr);
2803 }
2804 if (tls_only_flag || ssl_only_flag) {
2805 #ifdef TCPIPLIB
2806 socket_close(ttyfd);
2807 socket_close(tcpsrfd);
2808 #else /* TCPIPLIB */
2809 close(ttyfd);
2810 close(tcpsrfd);
2811 #endif /* TCPIPLIB */
2812 ttyfd = -1;
2813 wasclosed = 1;
2814 tcpsrfd = -1;
2815 tcpsrv_port = 0;
2816 return(-1);
2817 }
2818 /* we will continue to accept the connection */
2819 /* without SSL or TLS support unless required. */
2820 if ( TELOPT_DEF_S_ME_MODE(TELOPT_START_TLS) != TN_NG_MU )
2821 TELOPT_DEF_S_ME_MODE(TELOPT_START_TLS) = TN_NG_RF;
2822 if ( TELOPT_DEF_S_U_MODE(TELOPT_START_TLS) != TN_NG_MU )
2823 TELOPT_DEF_S_U_MODE(TELOPT_START_TLS) = TN_NG_RF;
2824 if ( TELOPT_DEF_C_ME_MODE(TELOPT_START_TLS) != TN_NG_MU )
2825 TELOPT_DEF_C_ME_MODE(TELOPT_START_TLS) = TN_NG_RF;
2826 if ( TELOPT_DEF_C_U_MODE(TELOPT_START_TLS) != TN_NG_MU )
2827 TELOPT_DEF_C_U_MODE(TELOPT_START_TLS) = TN_NG_RF;
2828 }
2829 }
2830 #endif /* CK_SSL */
2831
2832 printf("\nWaiting to Accept a TCP/IP connection on port %d ...\n",
2833 ntohs((unsigned short)service->s_port));
2834 saddrlen = sizeof(saddr);
2835
2836 #ifdef BSDSELECT
2837 tv.tv_sec = tv.tv_usec = 0L;
2838 if (timo < 0)
2839 tv.tv_usec = (long) -timo * 10000L;
2840 else
2841 tv.tv_sec = timo;
2842 debug(F101,"tcpsrv_open BSDSELECT","",timo);
2843 #else
2844 debug(F101,"tcpsrv_open not BSDSELECT","",timo);
2845 #endif /* BSDSELECT */
2846
2847 if (timo) {
2848 while (!ready_to_accept) {
2849 #ifdef BSDSELECT
2850 FD_ZERO(&rfds);
2851 FD_SET(tcpsrfd, &rfds);
2852 ready_to_accept =
2853 ((select(FD_SETSIZE,
2854 #ifdef HPUX
2855 #ifdef HPUX1010
2856 (fd_set *)
2857 #else
2858
2859 (int *)
2860 #endif /* HPUX1010 */
2861 #else
2862 #ifdef __DECC
2863 #ifdef INTSELECT
2864 (int *)
2865 #else /* def INTSELECT */
2866 (fd_set *)
2867 #endif /* def INTSELECT [else] */
2868 #endif /* __DECC */
2869 #endif /* HPUX */
2870 &rfds, NULL, NULL, &tv) > 0) &&
2871 FD_ISSET(tcpsrfd, &rfds));
2872 #else /* BSDSELECT */
2873 #ifdef IBMSELECT
2874 #define ck_sleepint 250
2875 ready_to_accept =
2876 (select(&tcpsrfd, 1, 0, 0,
2877 timo < 0 ? -timo :
2878 (timo > 0 ? timo * 1000L : ck_sleepint)) == 1
2879 );
2880 #else
2881 #ifdef BELLSELECT
2882 FD_ZERO(rfds);
2883 FD_SET(tcpsrfd, rfds);
2884 ready_to_accept =
2885 ((select(128, rfds, NULL, NULL, timo < 0 ? -timo :
2886 (timo > 0 ? timo * 1000L)) > 0) &&
2887 FD_ISSET(tcpsrfd, rfds));
2888 #else
2889 /* Try this - what's the worst that can happen... */
2890
2891 FD_ZERO(&rfds);
2892 FD_SET(tcpsrfd, &rfds);
2893 ready_to_accept =
2894 ((select(FD_SETSIZE,
2895 (fd_set *) &rfds, NULL, NULL, &tv) > 0) &&
2896 FD_ISSET(tcpsrfd, &rfds));
2897
2898 #endif /* BELLSELECT */
2899 #endif /* IBMSELECT */
2900 #endif /* BSDSELECT */
2901 }
2902 }
2903 if (ready_to_accept || timo == 0) {
2904 if ((ttyfd = accept(tcpsrfd,
2905 (struct sockaddr *)&saddr,&saddrlen)) < 0) {
2906 i = errno; /* save error code */
2907 #ifdef TCPIPLIB
2908 socket_close(tcpsrfd);
2909 #else /* TCPIPLIB */
2910 close(tcpsrfd);
2911 #endif /* TCPIPLIB */
2912 ttyfd = -1;
2913 wasclosed = 1;
2914 tcpsrfd = -1;
2915 tcpsrv_port = 0;
2916 errno = i; /* and report this error */
2917 debug(F101,"tcpsrv_open accept errno","",errno);
2918 return(-1);
2919 }
2920 setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
2921
2922 #ifndef NOTCPOPTS
2923 #ifndef datageneral
2924 #ifdef SOL_SOCKET
2925 #ifdef TCP_NODELAY
2926 no_delay(ttyfd,tcp_nodelay);
2927 debug(F101,"tcpsrv_open no_delay","",tcp_nodelay);
2928 #endif /* TCP_NODELAY */
2929 #ifdef SO_KEEPALIVE
2930 keepalive(ttyfd,tcp_keepalive);
2931 debug(F101,"tcpsrv_open keepalive","",tcp_keepalive);
2932 #endif /* SO_KEEPALIVE */
2933 #ifdef SO_LINGER
2934 ck_linger(ttyfd,tcp_linger, tcp_linger_tmo);
2935 debug(F101,"tcpsrv_open linger","",tcp_linger_tmo);
2936 #endif /* SO_LINGER */
2937 #ifdef SO_SNDBUF
2938 sendbuf(ttyfd,tcp_sendbuf);
2939 #endif /* SO_SNDBUF */
2940 #ifdef SO_RCVBUF
2941 recvbuf(ttyfd,tcp_recvbuf);
2942 #endif /* SO_RCVBUF */
2943 #endif /* SOL_SOCKET */
2944 #endif /* datageneral */
2945 #endif /* NOTCPOPTS */
2946
2947 ttnet = nett; /* TCP/IP (sockets) network */
2948 tcp_incoming = 1; /* This is an incoming connection */
2949 sstelnet = 1; /* Do server-side Telnet protocol */
2950
2951 /* See if the service is TELNET. */
2952 x = (unsigned short)service->s_port;
2953 service2 = getservbyname("telnet", "tcp");
2954 if (service2 && x == service2->s_port) {
2955 #ifdef COMMENT
2956 /* Jeff 2005/12/30 */
2957 if (ttnproto != NP_TCPRAW && /* Yes... */
2958 ttnproto != NP_SSL_RAW &&
2959 ttnproto != NP_TLS_RAW) /* and if raw port not requested */
2960 #else
2961 /* fdc 2005/12/04 */
2962 if (ttnproto != NP_TCPRAW) /* Yes and if raw port not requested */
2963 #endif /* */
2964 ttnproto = NP_TELNET; /* set protocol to TELNET. */
2965 }
2966 ckstrncpy(ipaddr,(char *)inet_ntoa(saddr.sin_addr),20);
2967 if (tcp_rdns) {
2968 if (!quiet) {
2969 printf(" Reverse DNS Lookup... ");
2970 fflush(stdout);
2971 }
2972 if (host = gethostbyaddr((char *)&saddr.sin_addr,4,PF_INET)) {
2973 host = ck_copyhostent(host);
2974 debug(F100,"tcpsrv_open gethostbyaddr != NULL","",0);
2975 if (!quiet) {
2976 printf("(OK)\n");
2977 fflush(stdout);
2978 }
2979 name[0] = '*';
2980 ckstrncpy(&name[1],host->h_name,78);
2981 ckstrncat(name,":",80-strlen(name));
2982 ckstrncat(name,p,80-strlen(name));
2983 if (!quiet
2984 #ifndef NOICP
2985 && !doconx
2986 #endif /* NOICP */
2987 )
2988 printf("%s connected on port %s\n",host->h_name,p);
2989 } else {
2990 if (!quiet) printf("Failed.\n");
2991 }
2992 } else if (!quiet) printf("(OK)\n");
2993
2994 if (!tcp_rdns || !host) {
2995 ckstrncpy(name,ipaddr,80);
2996 ckstrncat(name,":",80);
2997 ckstrncat(name,ckuitoa(ntohs(saddr.sin_port)),80);
2998 if (!quiet
2999 #ifndef NOICP
3000 && !doconx
3001 #endif /* NOICP */
3002 )
3003 printf("%s connected on port %d\n",ipaddr,ntohs(saddr.sin_port));
3004 }
3005 if (!quiet) fflush(stdout);
3006
3007 #ifdef CK_SECURITY
3008 /* Before Initialization Telnet/Rlogin Negotiations Init Kerberos */
3009 ck_auth_init((tcp_rdns && host && host->h_name && host->h_name[0]) ?
3010 (char *)host->h_name : ipaddr,
3011 ipaddr,
3012 uidbuf,
3013 ttyfd
3014 );
3015 #endif /* CK_SECURITY */
3016
3017 #ifdef CK_SSL
3018 if (ck_ssleay_is_installed() && !ssl_failed) {
3019 if (ck_ssl_incoming(ttyfd) < 0) {
3020 #ifdef TCPIPLIB
3021 socket_close(ttyfd);
3022 socket_close(tcpsrfd);
3023 #else /* TCPIPLIB */
3024 close(ttyfd);
3025 close(tcpsrfd);
3026 #endif /* TCPIPLIB */
3027 ttyfd = -1;
3028 wasclosed = 1;
3029 tcpsrfd = -1;
3030 tcpsrv_port = 0;
3031 return(-1);
3032 }
3033 }
3034 #endif /* CK_SSL */
3035
3036 #ifndef datageneral
3037 /* Find out our own IP address. */
3038 l_slen = sizeof(l_addr);
3039 bzero((char *)&l_addr, l_slen);
3040 #ifndef EXCELAN
3041 if (!getsockname(ttyfd, (struct sockaddr *)&l_addr, &l_slen)) {
3042 char * s = (char *)inet_ntoa(l_addr.sin_addr);
3043 ckstrncpy(myipaddr, s,20);
3044 debug(F110,"getsockname",myipaddr,0);
3045 }
3046 #endif /* EXCELAN */
3047 #endif /* datageneral */
3048
3049 if (tn_ini() < 0) /* Start TELNET negotiations. */
3050 if (ttchk() < 0) { /* Disconnected? */
3051 i = errno; /* save error code */
3052 #ifdef TCPIPLIB
3053 socket_close(tcpsrfd);
3054 #else /* TCPIPLIB */
3055 close(tcpsrfd);
3056 #endif /* TCPIPLIB */
3057 ttyfd = -1;
3058 wasclosed = 1;
3059 tcpsrfd = -1;
3060 tcpsrv_port = 0;
3061 errno = i; /* and report this error */
3062 debug(F101,"tcpsrv_open accept errno","",errno);
3063 return(-1);
3064 }
3065 debug(F101,"tcpsrv_open service","",x);
3066 if (*lcl < 0) /* Set local mode. */
3067 *lcl = 1;
3068
3069 #ifdef CK_KERBEROS
3070 #ifdef KRB5_U2U
3071 if ( ttnproto == NP_K5U2U ) {
3072 if (k5_user_to_user_server_auth() != 0) {
3073 i = errno; /* save error code */
3074 #ifdef TCPIPLIB
3075 socket_close(tcpsrfd);
3076 #else /* TCPIPLIB */
3077 close(tcpsrfd);
3078 #endif /* TCPIPLIB */
3079 ttyfd = -1;
3080 wasclosed = 1;
3081 tcpsrfd = -1;
3082 tcpsrv_port = 0;
3083 errno = i; /* and report this error */
3084 debug(F101,"tcpsrv_open accept errno","",errno);
3085 return(-1);
3086 }
3087 }
3088 #endif /* KRB5_U2U */
3089 #endif /* CK_KERBEROS */
3090 return(0); /* Done. */
3091 } else {
3092 i = errno; /* save error code */
3093 #ifdef TCPIPLIB
3094 socket_close(tcpsrfd);
3095 #else /* TCPIPLIB */
3096 close(tcpsrfd);
3097 #endif /* TCPIPLIB */
3098 ttyfd = -1;
3099 wasclosed = 1;
3100 tcpsrfd = -1;
3101 tcpsrv_port = 0;
3102 errno = i; /* and report this error */
3103 debug(F101,"tcpsrv_open accept errno","",errno);
3104 return(-1);
3105 }
3106 }
3107 #endif /* NOLISTEN */
3108 #endif /* OS2 */
3109 #endif /* TCPSOCKET */
3110 #endif /* NONET */
3111
3112 #ifdef TCPSOCKET
3113 char *
ckname2addr(name)3114 ckname2addr(name) char * name;
3115 {
3116 #ifdef HPUX5
3117 return("");
3118 #else
3119 struct hostent *host;
3120
3121 if (name == NULL || *name == '\0')
3122 return("");
3123
3124 host = gethostbyname(name);
3125 if ( host ) {
3126 host = ck_copyhostent(host);
3127 return(inet_ntoa(*((struct in_addr *) host->h_addr)));
3128 }
3129 return("");
3130 #endif /* HPUX5 */
3131 }
3132
3133 char *
ckaddr2name(addr)3134 ckaddr2name(addr) char * addr;
3135 {
3136 #ifdef HPUX5
3137 return("");
3138 #else
3139 struct hostent *host;
3140 struct in_addr sin_addr;
3141
3142 if (addr == NULL || *addr == '\0')
3143 return("");
3144
3145 sin_addr.s_addr = inet_addr(addr);
3146 host = gethostbyaddr((char *)&sin_addr,4,AF_INET);
3147 if (host) {
3148 host = ck_copyhostent(host);
3149 return((char *)host->h_name);
3150 }
3151 return("");
3152 #endif /* HPUX5 */
3153 }
3154 #endif /* TCPSOCKET */
3155
3156 unsigned long peerxipaddr = 0L;
3157
3158 char *
ckgetpeer()3159 ckgetpeer() {
3160 #ifdef TCPSOCKET
3161 static char namebuf[256];
3162 static struct hostent *host;
3163 static struct sockaddr_in saddr;
3164 #ifdef GPEERNAME_T
3165 static GPEERNAME_T saddrlen;
3166 #else
3167 #ifdef PTX
3168 static size_t saddrlen;
3169 #else
3170 #ifdef AIX42
3171 /* It's size_t in 4.2 but int in 4.1 and earlier. */
3172 /* Note: the 4.2 man page lies; believe socket.h. */
3173 static size_t saddrlen;
3174 #else
3175 #ifdef UNIXWARE
3176 static size_t saddrlen;
3177 #else /* UNIXWARE */
3178 #ifdef DEC_TCPIP
3179 /* 2010-03-08 SMS.
3180 * Coincidentally, the condition for integer arguments in select(),
3181 * which is actually "defined( _DECC_V4_SOURCE)", works for an integer
3182 * argument in getpeername(). Sadly, due to a lack of foresight,
3183 * "defined( _DECC_V4_SOURCE)" doesn't work with DEC C V4.0, so the
3184 * user-specified INTSELECT is used instead. Most likely, "size_t"
3185 * should be used instead of "unsigned int", but I'm a coward.
3186 */
3187 #ifdef INTSELECT
3188 static int saddrlen;
3189 #else /* def INTSELECT */
3190 static unsigned int saddrlen;
3191 #endif /* def INTSELECT [else] */
3192 #else
3193 #ifdef MACOSX10
3194 static unsigned int saddrlen;
3195 #else
3196 #ifdef CK_64BIT
3197 static socklen_t saddrlen;
3198 #else
3199 static int saddrlen;
3200 #endif /* CK_64BIT */
3201 #endif /* MACOSX10 */
3202 #endif /* DEC_TCPIP */
3203 #endif /* UNIXWARE */
3204 #endif /* AIX42 */
3205 #endif /* PTX */
3206 #endif /* GPEERNAME_T */
3207 saddrlen = sizeof(saddr);
3208 if (getpeername(ttyfd,(struct sockaddr *)&saddr,&saddrlen) < 0) {
3209 debug(F111,"ckgetpeer failure",ckitoa(ttyfd),errno);
3210 return(NULL);
3211 }
3212 host = gethostbyaddr((char *)&saddr.sin_addr,4,AF_INET);
3213 if (host) {
3214 host = ck_copyhostent(host);
3215 ckstrncpy(namebuf,(char *)host->h_name,80);
3216 } else {
3217 ckstrncpy(namebuf,(char *)inet_ntoa(saddr.sin_addr),80);
3218 }
3219 peerxipaddr = ntohl(saddr.sin_addr.s_addr);
3220 debug(F111,"ckgetpeer",namebuf,peerxipaddr);
3221 return(namebuf);
3222 #else
3223 return(NULL);
3224 #endif /* TCPSOCKET */
3225 }
3226
3227 /* Get fully qualified IP hostname */
3228
3229 #ifndef NONET
3230 char *
3231 #ifdef CK_ANSIC
ckgetfqhostname(char * name)3232 ckgetfqhostname(char * name)
3233 #else
3234 ckgetfqhostname(name) char * name;
3235 #endif /* CK_ANSIC */
3236 {
3237 #ifdef NOCKGETFQHOST
3238
3239 return(name);
3240
3241 #else /* If the following code dumps core, define NOCKGETFQHOST and rebuild. */
3242
3243 static char namebuf[256];
3244 struct hostent *host=NULL;
3245 struct sockaddr_in r_addr;
3246 int i;
3247
3248 debug(F110,"ckgetfqhn()",name,0);
3249
3250 ckstrncpy(namebuf,name,256);
3251 namebuf[255] = '\0';
3252 i = ckindex(":",namebuf,0,0,0);
3253 if (i)
3254 namebuf[i-1] = '\0';
3255
3256 bzero((char *)&r_addr, sizeof(r_addr));
3257
3258 host = gethostbyname(namebuf);
3259 if (host) {
3260 host = ck_copyhostent(host);
3261 debug(F100,"ckgetfqhn() gethostbyname != NULL","",0);
3262 r_addr.sin_family = host->h_addrtype;
3263 #ifdef HADDRLIST
3264 #ifdef h_addr
3265 /* This is for trying multiple IP addresses - see <netdb.h> */
3266 if (!(host->h_addr_list))
3267 goto exit_func;
3268 bcopy(host->h_addr_list[0],
3269 (caddr_t)&r_addr.sin_addr,
3270 host->h_length
3271 );
3272 #else
3273 bcopy(host->h_addr, (caddr_t)&r_addr.sin_addr, host->h_length);
3274 #endif /* h_addr */
3275 #else /* HADDRLIST */
3276 bcopy(host->h_addr, (caddr_t)&r_addr.sin_addr, host->h_length);
3277 #endif /* HADDRLIST */
3278 #ifdef COMMENT
3279 #ifndef EXCELAN
3280 debug(F111,"BCOPY","host->h_addr",host->h_addr);
3281 #endif /* EXCELAN */
3282 debug(F111,"BCOPY"," (caddr_t)&r_addr.sin_addr",
3283 (caddr_t)&r_addr.sin_addr);
3284 #endif /* COMMENT */
3285 debug(F111,"BCOPY","host->h_length",host->h_length);
3286
3287 #ifdef NT
3288 /* Windows 95/98 requires a 1 second wait between calls to Microsoft */
3289 /* provided DNS functions. Otherwise, the TTL of the DNS response */
3290 /* is ignored. */
3291 if (isWin95())
3292 sleep(1);
3293 #endif /* NT */
3294 host = gethostbyaddr((char *)&r_addr.sin_addr,4,PF_INET);
3295 if (host) {
3296 host = ck_copyhostent(host);
3297 debug(F100,"ckgetfqhn() gethostbyaddr != NULL","",0);
3298 ckstrncpy(namebuf, host->h_name, 256);
3299 }
3300 }
3301
3302 #ifdef HADDRLIST
3303 #ifdef h_addr
3304 exit_func:
3305 #endif /* h_addr */
3306 #endif /* HADDRLIST */
3307
3308 if (i > 0)
3309 ckstrncat(namebuf,&name[i-1],256-strlen(namebuf)-strlen(&name[i-1]));
3310 debug(F110,"ckgetfqhn()",namebuf,0);
3311 return(namebuf);
3312 #endif /* NOCKGETFQHOST */
3313 }
3314
3315 VOID
3316 #ifdef CK_ANSIC
setnproto(char * p)3317 setnproto(char * p)
3318 #else
3319 setnproto(p) char * p;
3320 #endif /* CK_ANSIC */
3321 {
3322 if (!isdigit(*p)) {
3323 if (!strcmp("kermit",p))
3324 ttnproto = NP_KERMIT;
3325 else if (!strcmp("telnet",p))
3326 ttnproto = NP_TELNET;
3327 else if (!strcmp("http",p))
3328 ttnproto = NP_TCPRAW;
3329 #ifdef RLOGCODE
3330 else if (!strcmp("login",p))
3331 ttnproto = NP_RLOGIN;
3332 #endif /* RLOGCODE */
3333 #ifdef CK_SSL
3334 /* Commonly used SSL ports (might not be in services file) */
3335 else if (!strcmp("https",p)) {
3336 ttnproto = NP_SSL_RAW;
3337 ssl_only_flag = 1;
3338 } else if (!strcmp("ssl-telnet",p)) {
3339 ttnproto = NP_TELNET;
3340 ssl_only_flag = 1;
3341 } else if (!strcmp("telnets",p)) {
3342 ttnproto = NP_TELNET;
3343 ssl_only_flag = 1;
3344 }
3345 #endif /* CK_SSL */
3346 #ifdef CK_KERBEROS
3347 #ifdef RLOGCODE
3348 else if (!strcmp("klogin",p)) {
3349 if (ck_krb5_is_installed())
3350 ttnproto = NP_K5LOGIN;
3351 else if (ck_krb4_is_installed())
3352 ttnproto = NP_K4LOGIN;
3353 else
3354 ttnproto = NP_RLOGIN;
3355 } else if (!strcmp("eklogin",p)) {
3356 if (ck_krb5_is_installed())
3357 ttnproto = NP_EK5LOGIN;
3358 else if (ck_krb4_is_installed())
3359 ttnproto = NP_EK4LOGIN;
3360 else
3361 ttnproto = NP_RLOGIN;
3362 }
3363 #endif /* RLOGCODE */
3364 #endif /* CK_KERBEROS */
3365 else
3366 ttnproto = NP_NONE;
3367 } else {
3368 switch (atoi(p)) {
3369 case 23: /* Telnet */
3370 ttnproto = NP_TELNET;
3371 break;
3372 case 513:
3373 ttnproto = NP_RLOGIN;
3374 break;
3375 case 1649:
3376 ttnproto = NP_KERMIT;
3377 break;
3378 #ifdef CK_SSL
3379 case 443:
3380 #ifdef COMMENT
3381 /* Jeff 2005/12/30 */
3382 ttnproto = NP_SSL_RAW;
3383 #else
3384 /* fdc 2005/12/04 */
3385 ttnproto = NP_SSL;
3386 #endif /* COMMENT */
3387 ssl_only_flag = 1;
3388 break;
3389 case 151:
3390 case 992:
3391 ttnproto = NP_TELNET;
3392 ssl_only_flag = 1;
3393 break;
3394 #endif /* CK_SSL */
3395 #ifdef CK_KERBEROS
3396 case 543:
3397 if (ck_krb5_is_installed())
3398 ttnproto = NP_K5LOGIN;
3399 else if (ck_krb4_is_installed())
3400 ttnproto = NP_K4LOGIN;
3401 else
3402 ttnproto = NP_RLOGIN;
3403 break;
3404 case 2105:
3405 if (ck_krb5_is_installed())
3406 ttnproto = NP_EK5LOGIN;
3407 else if (ck_krb4_is_installed())
3408 ttnproto = NP_EK4LOGIN;
3409 else
3410 ttnproto = NP_RLOGIN;
3411 break;
3412 #endif /* CK_KERBEROS */
3413 case 80: /* HTTP */
3414 ttnproto = NP_TCPRAW;
3415 break;
3416 default:
3417 ttnproto = NP_NONE;
3418 break;
3419 }
3420 }
3421 }
3422
3423 /* ckgetservice() is used to determine the port number for a given */
3424 /* service taking into account the use of DNS SRV records. */
3425
3426 static struct servent servrec;
3427 static struct servent *
ckgetservice(hostname,servicename,ip,iplen)3428 ckgetservice(hostname, servicename, ip, iplen)
3429 char *hostname; char * servicename; char * ip; int iplen;
3430 {
3431 struct servent * service = NULL;
3432 #ifdef CK_DNS_SRV
3433 struct sockaddr * dns_addrs = NULL;
3434 int dns_naddrs = 0;
3435 #endif /* CK_DNS_SRV */
3436
3437 if (isdigit(*servicename)) { /* Use socket number without lookup */
3438 service = &servrec;
3439 service->s_port = htons((unsigned short)atoi(servicename));
3440 } else { /* Otherwise lookup the service name */
3441 #ifdef CK_DNS_SRV
3442 if (tcp_dns_srv && !quiet) {
3443 printf(" DNS SRV Lookup... ");
3444 fflush(stdout);
3445 }
3446 if (tcp_dns_srv &&
3447 locate_srv_dns(hostname,
3448 servicename,
3449 "tcp",
3450 &dns_addrs,
3451 &dns_naddrs
3452 )
3453 ) {
3454 /* Use the first one. Eventually we should cycle through all */
3455 /* the returned IP addresses and port numbers. */
3456 struct sockaddr_in *sin = NULL;
3457 #ifdef BETADEBUG
3458 int i;
3459 printf("\r\n");
3460 for ( i=0;i<dns_naddrs;i++ ) {
3461 sin = (struct sockaddr_in *) &dns_addrs[i];
3462 printf("dns_addrs[%d] = %s %d\r\n", i,
3463 (char *)inet_ntoa(sin->sin_addr),
3464 ntohs(sin->sin_port));
3465 }
3466 #endif /* BETADEBUG */
3467 sin = (struct sockaddr_in *) &dns_addrs[0];
3468 if ( ip && iplen > 0 )
3469 ckstrncpy(ip,(char *)inet_ntoa(sin->sin_addr),iplen);
3470 service = &servrec;
3471 service->s_port = sin->sin_port;
3472
3473 free(dns_addrs);
3474 dns_addrs = NULL;
3475 dns_naddrs = 0;
3476 } else
3477 #endif /* CK_DNS_SRV */
3478 service = getservbyname(servicename, "tcp");
3479 }
3480 if (!service) {
3481 if (!ckstrcmp("kermit",servicename,-1,0)) { /* Kermit service port */
3482 service = &servrec;
3483 service->s_port = htons(1649);
3484 } else if (!ckstrcmp("telnet",servicename,-1,0)) { /* Telnet port */
3485 service = &servrec;
3486 service->s_port = htons(23);
3487 } else if (!ckstrcmp("http",servicename,-1,0)) {
3488 service = &servrec;
3489 service->s_port = htons(80);
3490 }
3491 #ifdef RLOGCODE
3492 else if (!ckstrcmp("login",servicename,-1,0)) {
3493 service = &servrec;
3494 service->s_port = htons(513);
3495 }
3496 #endif /* RLOGCODE */
3497 #ifdef CK_SSL
3498 /* Commonly used SSL ports (might not be in services file) */
3499 else if (!ckstrcmp("https",servicename,-1,0)) {
3500 service = &servrec;
3501 service->s_port = htons(443);
3502 } else if (!ckstrcmp("ssl-telnet",servicename,-1,0)) {
3503 service = &servrec;
3504 service->s_port = htons(151);
3505 } else if (!ckstrcmp("telnets",servicename,-1,0)) {
3506 service = &servrec;
3507 service->s_port = htons(992);
3508 }
3509 #endif /* CK_SSL */
3510 #ifdef CK_KERBEROS
3511 #ifdef RLOGCODE
3512 else if (!ckstrcmp("klogin",servicename,-1,0)) {
3513 service = &servrec;
3514 service->s_port = htons(543);
3515 } else if (!ckstrcmp("eklogin",servicename,-1,0)) {
3516 service = &servrec;
3517 service->s_port = htons(2105);
3518 }
3519 #endif /* RLOGCODE */
3520 #endif /* CK_KERBEROS */
3521 }
3522 return(service);
3523 }
3524
3525 /* N E T O P E N -- Open a network connection */
3526 /*
3527 Calling conventions same as ttopen(), except third argument is network
3528 type rather than modem type. Designed to be called from within ttopen.
3529 */
3530
3531 #define XXNAMELEN 256
3532 static char xxname[XXNAMELEN];
3533
3534 int
netopen(name,lcl,nett)3535 netopen(name, lcl, nett) char *name; int *lcl, nett; {
3536 char *p;
3537 int i, x, rc_inet_addr = 0, dns = 0;
3538 #ifdef TCPSOCKET
3539 int isconnect = 0;
3540 #ifdef SO_OOBINLINE
3541 int on = 1;
3542 #endif /* SO_OOBINLINE */
3543 struct servent *service=NULL;
3544 struct hostent *host=NULL;
3545 struct sockaddr_in r_addr;
3546 struct sockaddr_in sin;
3547 struct sockaddr_in l_addr;
3548 GSOCKNAME_T l_slen;
3549 #ifdef EXCELAN
3550 struct sockaddr_in send_socket;
3551 #endif /* EXCELAN */
3552
3553 #ifdef INADDRX
3554 /* inet_addr() is of type struct in_addr */
3555 #ifdef datageneral
3556 extern struct in_addr inet_addr();
3557 #else
3558 #ifdef HPUX5WINTCP
3559 extern struct in_addr inet_addr();
3560 #endif /* HPUX5WINTCP */
3561 #endif /* datageneral */
3562 struct in_addr iax;
3563 #else
3564 #ifdef INADDR_NONE
3565 struct in_addr iax;
3566 #else /* INADDR_NONE */
3567 long iax;
3568 #endif /* INADDR_NONE */
3569 #endif /* INADDRX */
3570 #endif /* TCPSOCKET */
3571
3572 #ifdef COMMENT
3573 /* This causes big trouble */
3574 #ifndef INADDR_NONE
3575 #define INADDR_NONE 0xffffffff
3576 #endif /* INADDR_NONE */
3577 #endif /* COMMENT */
3578
3579 #ifdef SUNX25 /* Code for SunLink X.25 support */
3580 #define X29PID 1 /* X.29 Protocol ID */
3581 _PROTOTYP(SIGTYP x25oobh, (int) );
3582 CONN_DB x25host;
3583 #ifndef X25_WR_FACILITY
3584 FACILITY x25facil;
3585 #else
3586 FACILITY_DB x25facil;
3587 #endif /* X25_WR_FACILITY */
3588 static int needh = 1;
3589 PID_T pid;
3590 extern int linkid, lcn, x25ver;
3591 #endif /* SUNX25 */
3592 #ifdef ANYX25
3593 extern int revcall, closgr, cudata;
3594 extern char udata[];
3595 #endif /* ANYX25 */
3596
3597 #ifdef IBMX25 /* Variables for IBM X25 */
3598 extern int x25port; /* Logical port to use */
3599 extern x25addr_t local_nua; /* Local X.25 address */
3600 extern x25addr_t remote_nua; /* Remote X.25 address */
3601 extern char x25name[]; /* X25 device name (sx25a0) */
3602 extern char x25dev[]; /* X25 device file /dev/x25pkt */
3603 ulong bind_flags = 0; /* Flags for binding the X25 stream */
3604 ulong token = 0; /* Temporary return code */
3605 #endif /* IBMX25 */
3606
3607 debug(F101,"netopen nett","",nett);
3608 *ipaddr = '\0'; /* Initialize IP address string */
3609
3610 #ifdef SUNX25
3611 if (nett == NET_SX25) { /* If network type is X.25 */
3612 netclos(); /* Close any previous net connection */
3613 ttnproto = NP_NONE; /* No protocol selected yet */
3614
3615 /* Set up host structure */
3616 bzero((char *)&x25host,sizeof(x25host));
3617 if ((x25host.hostlen = pkx121(name,x25host.host)) < 0) {
3618 fprintf (stderr,"Invalid X.121 host address %s\n",name);
3619 errno = 0;
3620 return (-1);
3621 }
3622 x25host.datalen = X29PIDLEN;
3623 x25host.data[0] = X29PID;
3624
3625 /* Set call user data if specified */
3626 if (cudata) {
3627 ckstrncpy((char *)x25host.data+X29PIDLEN,udata,(int)strlen(udata));
3628 x25host.datalen += (int)strlen(udata);
3629 }
3630
3631 /* Open SunLink X.25 socket */
3632 if (!quiet && *name) {
3633 printf(" Trying %s... ", name);
3634 fflush(stdout);
3635 }
3636 if ((ttyfd = socket(AF_X25, SOCK_STREAM, 0)) < 0) {
3637 debug(F101,"netopen socket error","",errno);
3638 perror ("X.25 socket error");
3639 return (-1);
3640 }
3641
3642 /* Setting X.25 out-of-band data handler */
3643 pid = getpid();
3644 if (ioctl(ttyfd,SIOCSPGRP,&pid)) {
3645 perror("X.25 set process group id error");
3646 return(-1);
3647 }
3648 (VOID) signal(SIGURG,x25oobh);
3649
3650 /* Set reverse charge call and closed user group if requested */
3651 bzero ((char *)&x25facil,sizeof(x25facil));
3652
3653 #ifndef X25_WR_FACILITY
3654 /* New SunLink (7.0 or 8.0, not sure which)... */
3655 x25facil.type = T_REVERSE_CHARGE; /* Reverse Charge */
3656 x25facil.f_reverse_charge = revcall ? 1 : 0;
3657 if (ioctl(ttyfd,X25_SET_FACILITY,&x25facil) < 0) {
3658 perror ("Setting X.25 reverse charge");
3659 return (-1);
3660 }
3661 if (closgr > -1) { /* Closed User Group (Outgoing) */
3662 bzero ((char *)&x25facil,sizeof(x25facil));
3663 x25facil.type = T_CUG;
3664 x25facil.f_cug_req = CUG_REQ_ACS;
3665 x25facil.f_cug_index = closgr;
3666 if (ioctl(ttyfd,X25_SET_FACILITY,&x25facil) < 0) {
3667 perror ("Setting X.25 closed user group");
3668 return (-1);
3669 }
3670 }
3671 #else
3672 /* Old SunLink 6.0 (or 7.0?)... */
3673 if (revcall) x25facil.reverse_charge = revcall;
3674 if (closgr > -1) {
3675 x25facil.cug_req = 1;
3676 x25facil.cug_index = closgr;
3677 }
3678 if (ioctl(ttyfd,X25_WR_FACILITY,&x25facil) < 0) {
3679 perror ("Setting X.25 facilities");
3680 return (-1);
3681 }
3682 #endif /* X25_WR_FACILITY */
3683
3684 /* Need X.25 header with bits Q and M */
3685 if (ioctl (ttyfd,X25_HEADER,&needh) < 0) {
3686 perror ("Setting X.25 header");
3687 return (-1);
3688 }
3689
3690 /* Connects to remote host via SunLink X.25 */
3691 if (connect(ttyfd,(struct sockaddr *)&x25host,sizeof(x25host)) < 0) {
3692 i = errno;
3693 debug(F101,"netopen connect errno","",i);
3694 if (i) {
3695 perror("netopen x25 connect");
3696 x25diag();
3697 }
3698 (VOID) netclos();
3699 ttyfd = -1;
3700 wasclosed = 1;
3701 ttnproto = NP_NONE;
3702 errno = i;
3703 return (-1);
3704 }
3705
3706 /* Get X.25 link identification used for the connection */
3707 if (ioctl(ttyfd,X25_GET_LINK,&linkid) < 0) {
3708 perror ("Getting X.25 link id");
3709 return (-1);
3710 }
3711
3712 /* Get X.25 logical channel number used for the connection */
3713 if (ioctl(ttyfd,X25_RD_LCGN,&lcn) < 0) {
3714 perror ("Getting X.25 lcn");
3715 return (-1);
3716 }
3717
3718 /* Get SunLink X.25 version */
3719 if (ioctl(ttyfd,X25_VERSION,&x25ver) < 0) {
3720 perror ("Getting SunLink X.25 version");
3721 return (-1);
3722 }
3723 ttnet = nett; /* Sunlink X.25 network */
3724 ttnproto = NP_X3; /* PAD X.3, X.28, X.29 protocol */
3725 if (lcl) if (*lcl < 0) *lcl = 1; /* Local mode */
3726 return(0);
3727 } else /* Note that SUNX25 support can coexist with TCP/IP support. */
3728 #endif /* SUNX25 */
3729
3730 #ifdef IBMX25
3731 /* riehm */
3732 if (nett == NET_IX25) { /* IBM AIX X.25 */
3733 netclos(); /* Close any previous net connection */
3734 ttnproto = NP_NONE; /* No protocol selected yet */
3735
3736 /* find out who we are - this is not so easy on AIX */
3737 /* riehm: need to write the code that finds this out
3738 * automatically, or at least allow it to be configured
3739 * somehow
3740 */
3741 if (!local_nua[0] && !x25local_nua(local_nua)) {
3742 return(-1);
3743 }
3744
3745 /* Initialise the X25 API (once per process? once per connection?) */
3746
3747 debug(F110, "Opening ", x25dev, 0 );
3748 /* set O_NDELAY to allow polling? */
3749 if ((ttyfd = open(x25dev, O_RDWR)) < 0) {
3750 perror ("X.25 device open error");
3751 debug(F101,"netopen: device open error","",errno);
3752 return (-1);
3753 }
3754
3755 /* push the NPI onto the STREAM */
3756 if (ioctl(ttyfd,I_PUSH,"npi") < 0 ) {
3757 close(ttyfd);
3758 ttyfd = -1;
3759 wasclosed = 1;
3760 perror( "kermit: netopen(): couldn't push npi on the X25 stream" );
3761 debug(F101,"netopen: can't push npi on the X25 stream","",errno);
3762 return (-1);
3763 }
3764
3765 /* set up server mode - bind the x25 port and wait for
3766 * incoming connections
3767 */
3768 if (name[0] == '*') { /* Server */
3769 /* set up a server - see the warning in x25bind() */
3770 bind_flags |= TOKEN_REQUEST;
3771
3772 /* bind kermit to the local X25 address */
3773 token = x25bind(ttyfd,
3774 local_nua,
3775 udata,
3776 (int)strlen( udata ),
3777 1,
3778 x25port,
3779 bind_flags
3780 );
3781 if (token < 0) {
3782 debug(F100,"netopen: couldn't bind to local X25 address","",0);
3783 netclos();
3784 return(-1);
3785 }
3786 /* Currently not connected to a remote host */
3787
3788 remote_nua[0] = '\0';
3789
3790 /* store the fd so that incoming calls can have their own fd
3791 * This is almost support for a true server (ie: a'la ftpd)
3792 * but we're not quite there yet.
3793 * used in netclos()
3794 */
3795 x25serverfd = ttyfd;
3796 /*
3797 * wait for an incoming call
3798 * this should happen in the "server" command and not in
3799 * the "set host *" command.
3800 */
3801 if ((ttyfd = x25getcall(ttyfd)) < 0) {
3802 netclos();
3803 return(-1);
3804 }
3805 } else { /* Client */
3806 /* Bind kermit to the local X25 address */
3807 token = x25bind(
3808 ttyfd,
3809 local_nua,
3810 (char *)NULL,
3811 0,
3812 0,
3813 x25port,
3814 bind_flags
3815 );
3816 if (token < 0) {
3817 debug(F100,"netopen: couldn't bind to local X25 address","",0);
3818 netclos();
3819 return(-1);
3820 }
3821 /* riehm: this should be done via the CONNECT command, not HOST! */
3822 {
3823 x25serverfd = 0;
3824 /* call the remote host */
3825 /* name == address of remote host as char* */
3826 if (x25call(ttyfd, name, udata) < 0 ) {
3827 debug(F100,
3828 "netopen: couldn't connect to remote X25 address",
3829 "", 0);
3830 netclos();
3831 return(-1);
3832 }
3833 strcpy(remote_nua, name);
3834 }
3835 }
3836 ttnet = nett; /* AIX X.25 network */
3837 if (lcl) if (*lcl < 0) *lcl = 1; /* Local mode */
3838 return(0);
3839
3840 } else /* Note that IBMX25 support can coexist with TCP/IP support. */
3841 #endif /* IBMX25 */
3842
3843 /* Add support for other networks here. */
3844
3845 if (nett != NET_TCPB) return(-1); /* BSD socket support */
3846
3847 #ifdef TCPSOCKET
3848 netclos(); /* Close any previous connection. */
3849 ckstrncpy(namecopy, name, NAMECPYL); /* Copy the hostname. */
3850 debug(F110,"netopen namecopy",namecopy,0);
3851
3852 #ifndef NOLISTEN
3853 if (name[0] == '*')
3854 return(tcpsrv_open(name, lcl, nett, 0));
3855 #endif /* NOLISTEN */
3856
3857 p = namecopy; /* Was a service requested? */
3858 while (*p != '\0' && *p != ':') p++; /* Look for colon */
3859 if (*p == ':') { /* Have a colon */
3860 debug(F110,"netopen name has colon",namecopy,0);
3861 *p++ = '\0'; /* Get service name or number */
3862 #ifdef CK_URL
3863 /*
3864 Here we have to check for various popular syntaxes:
3865 host:port (our original syntax)
3866 URL such as telnet:host or telnet://host/
3867 Or even telnet://user:password@host:port/path/
3868 Or a malformed URL such as generated by Netscape 4.0 like:
3869 telnet:telnet or telnet::host.
3870 */
3871
3872 /*
3873 * REPLACE THIS CODE WITH urlparse() but not on the day of the
3874 * C-Kermit 8.0 RELEASE.
3875 */
3876
3877 if (*p == ':') /* a second colon */
3878 *p++ = '\0'; /* get rid of that one too */
3879 while (*p == '/') *p++ = '\0'; /* and slashes */
3880 x = strlen(p); /* Length of remainder */
3881 if (p[x-1] == '/') /* If there is a trailing slash */
3882 p[x-1] = '\0'; /* remove it. */
3883 debug(F110,"netopen namecopy after stripping",namecopy,0);
3884 debug(F110,"netopen p after stripping",p,0);
3885 service = getservbyname(namecopy,"tcp");
3886 if (service ||
3887 #ifdef RLOGCODE
3888 !ckstrcmp("rlogin",namecopy,NAMECPYL,0) ||
3889 #endif /* RLOGCODE */
3890 #ifdef CK_SSL
3891 !ckstrcmp("telnets",namecopy,NAMECPYL,0) ||
3892 #endif /* CK_SSL */
3893 !ckstrcmp("iksd",namecopy,NAMECPYL,0)
3894 ) {
3895 char temphost[256], tempservice[80], temppath[256];
3896 char * q = p, *r = p, *w = p;
3897 int uidfound=0;
3898 extern char pwbuf[];
3899 extern int pwflg, pwcrypt;
3900
3901 if (ttnproto == NP_DEFAULT)
3902 setnproto(namecopy);
3903
3904 /* Check for userid and possibly password */
3905 while (*p != '\0' && *p != '@')
3906 p++; /* look for @ */
3907 if (*p == '@') {
3908 /* found username and perhaps password */
3909 debug(F110,"netopen namecopy found @","",0);
3910 *p = '\0';
3911 p++;
3912 while (*w != '\0' && *w != ':')
3913 w++;
3914 if (*w == ':')
3915 *w++ = '\0';
3916 /* r now points to username, save it and the password */
3917 debug(F110,"netopen namecopy username",r,0);
3918 debug(F110,"netopen namecopy password",w,0);
3919 uidfound=1;
3920 if ( strcmp(uidbuf,r) || *w )
3921 ckstrncpy(pwbuf,w,PWBUFL+1);
3922 ckstrncpy(uidbuf,r,UIDBUFLEN);
3923 pwflg = 1;
3924 pwcrypt = 0;
3925 q = p; /* Host after user and pwd */
3926 } else {
3927 p = q; /* No username or password */
3928 }
3929 /* Now we must look for the optional port. */
3930 debug(F110,"netopen x p",p,0);
3931 debug(F110,"netopen x q",q,0);
3932
3933 /* Look for the port/service or a file/directory path */
3934 while (*p != '\0' && *p != ':' && *p != '/')
3935 p++;
3936 if (*p == ':') {
3937 debug(F110,"netopen found port",q,0);
3938 *p++ = '\0'; /* Found a port name or number */
3939 r = p;
3940
3941 /* Look for the end of port/service or a file/directory path */
3942 while (*p != '\0' && *p != '/')
3943 p++;
3944 if (*p == '/')
3945 *p++ = '\0';
3946
3947 debug(F110,"netopen port",r,0);
3948 ckstrncpy(tempservice,r,80);
3949 ckstrncpy(temphost,q,256);
3950 ckstrncpy(temppath,p,256);
3951 ckstrncpy(namecopy,temphost,NAMECPYL);
3952 debug(F110,"netopen tempservice",tempservice,0);
3953 debug(F110,"netopen temphost",temphost,0);
3954 debug(F110,"netopen temppath",temppath,0);
3955
3956 /* move port/service to a buffer that won't go away */
3957 x = strlen(namecopy);
3958 p = namecopy + x + 1;
3959 ckstrncpy(p, tempservice, NAMECPYL - x);
3960 } else {
3961 /* Handle a path if we found one */
3962 if (*p == '/')
3963 *p++ = '\0';
3964 ckstrncpy(temppath,p,256);
3965
3966 /* We didn't find another port, but if q is a service */
3967 /* then assume that namecopy is actually a host. */
3968 if (getservbyname(q,"tcp")) {
3969 p = q;
3970 } else {
3971 #ifdef RLOGCODE
3972 /* rlogin is not a valid service */
3973 if (!ckstrcmp("rlogin",namecopy,6,0)) {
3974 ckstrncpy(namecopy,"login",NAMECPYL);
3975 }
3976 #endif /* RLOGCODE */
3977 /* iksd is not a valid service */
3978 if (!ckstrcmp("iksd",namecopy,6,0)) {
3979 ckstrncpy(namecopy,"kermit",NAMECPYL);
3980 }
3981 /* Reconstruct namecopy */
3982 ckstrncpy(tempservice,namecopy,80);
3983 ckstrncpy(temphost,q,256);
3984 ckstrncpy(namecopy,temphost,NAMECPYL);
3985 debug(F110,"netopen tempservice",tempservice,0);
3986 debug(F110,"netopen temphost",temphost,0);
3987 debug(F110,"netopen temppath",temppath,0);
3988
3989 /* move port/service to a buffer that won't go away */
3990 x = strlen(namecopy);
3991 p = namecopy + x + 1;
3992 ckstrncpy(p, tempservice, NAMECPYL - x - 1);
3993 }
3994 }
3995 debug(F110,"netopen URL result: host",namecopy,0);
3996 debug(F110,"netopen URL result: service",p,0);
3997 debug(F110,"netopen URL result: path",temppath,0);
3998
3999 #ifdef IKS_GET
4000 /* If we have set a path specified, we need to try to GET it */
4001 /* But we have another problem, we have to login first. How */
4002 /* do we specify that a login must be done before the GET? */
4003 /* The user's name if specified is in 'userid' and the */
4004 /* password if any is in 'pwbuf'. */
4005 if ( temppath[0] ) {
4006 extern int action;
4007 extern char * cmarg;
4008
4009 if ( !uidfound ) {
4010 /* If no userid was specified as part of the URL but
4011 * a path was specified, then we
4012 * set the user name to anonymous and the password
4013 * to the current userid.
4014 */
4015 ckstrncpy(pwbuf,uidbuf,PWBUFL);
4016 ckstrncat(pwbuf,"@",PWBUFL);
4017 pwflg = 1;
4018 pwcrypt = 0;
4019 ckstrncpy(uidbuf,"anonymous",UIDBUFLEN);
4020 }
4021
4022 /*
4023 * If a file path was specified we perform the GET
4024 * operation and then terminate the connection.
4025 *
4026 * If a directory was given instead of a file, then
4027 * we should REMOTE CD to the directory and list its
4028 * contents. But how do we tell the difference?
4029 */
4030 makestr(&cmarg,temppath);
4031 action = 'r';
4032 }
4033 #endif /* IKS_GET */
4034 }
4035 #endif /* CK_URL */
4036 } else { /* Otherwise use telnet */
4037 p = "telnet";
4038 }
4039 /*
4040 By the time we get here, namecopy[] should hold the null-terminated
4041 hostname or address, and p should point to the service name or number.
4042 */
4043 debug(F110,"netopen host",namecopy,0);
4044 debug(F110,"netopen service requested",p,0);
4045
4046 /* Use the service port to set the default protocol type if necessary */
4047 if (ttnproto == NP_DEFAULT)
4048 setnproto(p);
4049
4050 ckstrncpy(namecopy2,namecopy,NAMECPYL);
4051 service = ckgetservice(namecopy,p,namecopy,NAMECPYL);
4052 if (!service) {
4053 fprintf(stderr, "Can't find port for service %s\n", p);
4054 #ifdef TGVORWIN
4055 debug(F101,"netopen can't get service","",socket_errno);
4056 #else
4057 debug(F101,"netopen can't get service","",errno);
4058 #endif /* TGVORWIN */
4059 errno = 0; /* (rather than mislead) */
4060 return(-1);
4061 } else {
4062 if (!ckstrcmp(namecopy,namecopy2,-1,0))
4063 namecopy2[0] = '\0';
4064 ckstrncpy(svcbuf,ckuitoa(ntohs(service->s_port)),sizeof(svcbuf));
4065 debug(F110,"netopen service ok",svcbuf,0);
4066 }
4067
4068 #ifdef RLOGCODE
4069 if (service && !strcmp("login",p) && service->s_port != htons(513)) {
4070 fprintf(stderr,
4071 " Warning: login service on port %d instead of port 513\n",
4072 ntohs(service->s_port)
4073 );
4074 fprintf(stderr, " Edit SERVICES file if RLOGIN fails to connect.\n");
4075 debug(F101,"tcpsrv_open login on port","",ntohs(service->s_port));
4076 }
4077 #endif /* RLOGCODE */
4078
4079 #ifndef NOHTTP
4080 /* For HTTP connections we must preserve the original hostname and */
4081 /* service requested so we can include them in the Host header. */
4082 ckmakmsg(http_host_port,sizeof(http_host_port),namecopy,":",
4083 ckitoa(ntohs(service->s_port)),NULL);
4084
4085 /* 'namecopy' contains the name of the host to which we want to connect */
4086 /* 'svcbuf' contains the service name */
4087 /* 'service->s_port' contains the port number in network byte order */
4088
4089 /* If we are using an http proxy, we need to create a buffer containing */
4090 /* hostname:port-number */
4091 /* to pass to the http_connect() function. Then we need to replace */
4092 /* 'namecopy' with the name of the proxy server and the service->s_port */
4093 /* with the port number of the proxy (default port 80). */
4094
4095 if ( tcp_http_proxy ) {
4096 ckmakmsg(proxycopy,sizeof(proxycopy),namecopy,":",
4097 ckuitoa(ntohs(service->s_port)),NULL);
4098 ckstrncpy(namecopy,tcp_http_proxy,NAMECPYL);
4099
4100 p = namecopy; /* Was a service requested? */
4101 while (*p != '\0' && *p != ':') p++; /* Look for colon */
4102 if (*p == ':') { /* Have a colon */
4103 debug(F110,"netopen name has colon",namecopy,0);
4104 *p++ = '\0'; /* Get service name or number */
4105 } else {
4106 strcpy(++p,"http");
4107 }
4108
4109 service = ckgetservice(namecopy,p,namecopy,NAMECPYL);
4110 if (!service) {
4111 fprintf(stderr, "Can't find port for service %s\n", p);
4112 #ifdef TGVORWIN
4113 debug(F101,"netopen can't get service for proxy","",socket_errno);
4114 #else
4115 debug(F101,"netopen can't get service for proxy","",errno);
4116 #endif /* TGVORWIN */
4117 errno = 0; /* (rather than mislead) */
4118 return(-1);
4119 }
4120 ckstrncpy(p,ckuitoa(ntohs(service->s_port)),NAMECPYL-(p-namecopy));
4121
4122 }
4123 #endif /* NOHTTP */
4124
4125 /* Set up socket structure and get host address */
4126
4127 bzero((char *)&r_addr, sizeof(r_addr));
4128 debug(F100,"netopen bzero ok","",0);
4129 /*
4130 NOTE: Originally the inet_addr() check was #ifdef NT, but is enabled for
4131 all as of 20 Sep 97, to allow people to "set host" to a specific numeric IP
4132 address without going through the multihomed host sequence and winding up
4133 at a different place than the one requested.
4134 */
4135 #ifdef INADDR_NONE
4136 debug(F101,"netopen INADDR_NONE defined","",INADDR_NONE);
4137 #else /* INADDR_NONE */
4138 debug(F100,"netopen INADDR_NONE not defined","",0);
4139 #endif /* INADDR_NONE */
4140 #ifdef INADDRX
4141 debug(F100,"netopen INADDRX defined","",0);
4142 #else /* INADDRX */
4143 debug(F100,"netopen INADDRX not defined","",0);
4144 #endif /* INADDRX */
4145
4146 #ifndef NOMHHOST
4147 #ifdef INADDRX
4148 iax = inet_addr(namecopy);
4149 debug(F111,"netopen inet_addr",namecopy,iax.s_addr);
4150 #else /* INADDRX */
4151 #ifdef INADDR_NONE
4152 iax.s_addr = inet_addr(namecopy);
4153 debug(F111,"netopen inet_addr",namecopy,iax.s_addr);
4154 #else /* INADDR_NONE */
4155 #ifdef SOLARIS
4156 /* In Solaris inet_addr() is of type in_addr_t which is uint32_t */
4157 /* (unsigned) yet it returns -1 (signed) on failure. */
4158 /* It makes a difference in 64-bit builds. */
4159 rc_inet_addr = inet_addr(namecopy); /* Assign return code to an int */
4160 iax = (unsigned) rc_inet_addr; /* and from there to whatever.. */
4161 #else
4162 #ifndef datageneral
4163 iax = (unsigned int) inet_addr(namecopy);
4164 #else
4165 iax = -1L;
4166 #endif /* datageneral */
4167 #endif /* SOLARIS */
4168 debug(F111,"netopen rc_inet_addr",namecopy,rc_inet_addr);
4169 debug(F111,"netopen inet_addr",namecopy,iax);
4170 #endif /* INADDR_NONE */
4171 #endif /* INADDRX */
4172
4173 dns = 0;
4174 if (
4175 /* This might give warnings on 64-bit platforms but they should be harmless */
4176 /* because INADDR_NONE should be all 1's anyway, thus the OR part is */
4177 /* probably superfluous -- not sure why it's even there, maybe it should be */
4178 /* removed. */
4179 #ifdef SOLARIS
4180 rc_inet_addr == -1
4181 #else
4182 #ifdef INADDR_NONE
4183 iax.s_addr == INADDR_NONE /* || iax.s_addr == (unsigned long) -1L */
4184 #else /* INADDR_NONE */
4185 iax < 0
4186 #endif /* INADDR_NONE */
4187 #endif /* SOLARIS */
4188 ) {
4189 if (!quiet) {
4190 printf(" DNS Lookup... ");
4191 fflush(stdout);
4192 }
4193 if ((host = gethostbyname(namecopy)) != NULL) {
4194 debug(F110,"netopen gethostbyname != NULL",namecopy,0);
4195 host = ck_copyhostent(host);
4196 dns = 1; /* Remember we performed dns lookup */
4197 r_addr.sin_family = host->h_addrtype;
4198 if (tcp_rdns && host->h_name && host->h_name[0]
4199 #ifndef NOHTTP
4200 && (tcp_http_proxy == NULL)
4201 #endif /* NOHTTP */
4202 ) {
4203 #ifdef COMMENT
4204 ckstrncpy(xxname,host->h_name,XXNAMELEN);
4205 debug(F110,"netopen xxname[1]",xxname,0);
4206 if ((XXNAMELEN - (int)strlen(name)) > ((int)strlen(svcbuf)+1)){
4207 ckstrncat(xxname,":",XXNAMELEN - (int)strlen(xxname));
4208 ckstrncat(xxname,svcbuf,XXNAMELEN - (int)strlen(xxname));
4209 debug(F110,"netopen xxname[2]",xxname,0);
4210 }
4211 name = (char *)xxname;
4212 #else
4213 ckstrncpy(name,host->h_name,80); /* Bad Bad Bad */
4214 if ( (80-strlen(name)) > (strlen(svcbuf)+1) ) {
4215 ckstrncat(name,":",80-strlen(name));
4216 ckstrncat(name,svcbuf,80-strlen(name));
4217 }
4218 #endif /* COMMENT */
4219 }
4220 debug(F110,"netopen name after lookup",name,0);
4221
4222 #ifdef HADDRLIST
4223 #ifdef h_addr
4224 /* This is for trying multiple IP addresses - see <netdb.h> */
4225 if (!(host->h_addr_list))
4226 return(-1);
4227 bcopy(host->h_addr_list[0],
4228 (caddr_t)&r_addr.sin_addr,
4229 host->h_length
4230 );
4231 #else
4232 bcopy(host->h_addr, (caddr_t)&r_addr.sin_addr, host->h_length);
4233 #endif /* h_addr */
4234 #else /* HADDRLIST */
4235 #ifdef HPUX6
4236 r_addr.sin_addr.s_addr = (u_long)host->h_addr;
4237 #else /* HPUX6 */
4238 bcopy(host->h_addr, (caddr_t)&r_addr.sin_addr, host->h_length);
4239 #endif /* HPUX6 */
4240 #endif /* HADDRLIST */
4241
4242 #ifndef HPUX6
4243 debug(F111,"BCOPY","host->h_length",host->h_length);
4244 #endif /* HPUX6 */
4245 }
4246 }
4247 #endif /* NOMHHOST */
4248
4249 debug(F101,"netopen dns","",dns);
4250
4251 if (!dns) {
4252 #ifdef INADDRX
4253 /* inet_addr() is of type struct in_addr */
4254 struct in_addr ina;
4255 unsigned long uu;
4256 debug(F100,"netopen gethostbyname == NULL: INADDRX","",0);
4257 ina = inet_addr(namecopy);
4258 uu = *(unsigned int *)&ina;
4259 #else /* Not INADDRX */
4260 /* inet_addr() is unsigned long */
4261 unsigned long uu;
4262 debug(F100,"netopen gethostbyname == NULL: Not INADDRX","",0);
4263 uu = inet_addr(namecopy);
4264 #endif /* INADDRX */
4265 debug(F101,"netopen uu","",uu);
4266 if (
4267 #ifdef INADDR_NONE
4268 !(uu == INADDR_NONE || uu == (unsigned int) -1L)
4269 #else /* INADDR_NONE */
4270 uu != ((unsigned long)-1)
4271 #endif /* INADDR_NONE */
4272 ) {
4273 r_addr.sin_addr.s_addr = uu;
4274 r_addr.sin_family = AF_INET;
4275 } else {
4276 #ifdef VMS
4277 fprintf(stdout, "\r\n"); /* complete any previous message */
4278 #endif /* VMS */
4279 fprintf(stderr, "Can't get address for %s\n", namecopy);
4280 #ifdef TGVORWIN
4281 debug(F101,"netopen can't get address","",socket_errno);
4282 #else
4283 debug(F101,"netopen can't get address","",errno);
4284 #endif /* TGVORWIN */
4285 errno = 0; /* Rather than mislead */
4286 return(-1);
4287 }
4288 }
4289
4290 /* Get a file descriptor for the connection. */
4291
4292 r_addr.sin_port = service->s_port;
4293 ckstrncpy(ipaddr,(char *)inet_ntoa(r_addr.sin_addr),20);
4294 debug(F110,"netopen trying",ipaddr,0);
4295 if (!quiet && *ipaddr) {
4296 printf(" Trying %s... ", ipaddr);
4297 fflush(stdout);
4298 }
4299
4300 /* Loop to try additional IP addresses, if any. */
4301
4302 do {
4303 #ifdef EXCELAN
4304 send_socket.sin_family = AF_INET;
4305 send_socket.sin_addr.s_addr = 0;
4306 send_socket.sin_port = 0;
4307 if ((ttyfd = socket(SOCK_STREAM, (struct sockproto *)0,
4308 &send_socket, SO_REUSEADDR)) < 0)
4309 #else /* EXCELAN */
4310 #ifdef NT
4311 #ifdef COMMENT_X
4312 /*
4313 Must make sure that all sockets are opened in
4314 Non-overlapped mode since we use the standard
4315 C RTL functions to read and write data.
4316 But it doesn't seem to work as planned.
4317 */
4318 {
4319 int optionValue = SO_SYNCHRONOUS_NONALERT;
4320 if (setsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE,
4321 (char *) &optionValue, sizeof(optionValue))
4322 != NO_ERROR)
4323 return(-1);
4324 }
4325 #endif /* COMMENT */
4326 #endif /* NT */
4327
4328 if ((ttyfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
4329 #endif /* EXCELAN */
4330 {
4331 #ifdef EXCELAN
4332 experror("TCP socket error");
4333 #else
4334 #ifdef VMS
4335 fprintf(stdout, "\r\n"); /* complete any previous stdout */
4336 #endif /* VMS */
4337 #ifdef TGVORWIN
4338 #ifdef OLD_TWG
4339 errno = socket_errno;
4340 #endif /* OLD_TWG */
4341 socket_perror("TCP socket error");
4342 debug(F101,"netopen socket error","",socket_errno);
4343 #else
4344 perror("TCP socket error");
4345 debug(F101,"netopen socket error","",errno);
4346 #endif /* TGVORWIN */
4347 #endif /* EXCELAN */
4348 return (-1);
4349 }
4350 errno = 0;
4351
4352 #ifdef RLOGCODE
4353 /* Not part of the RLOGIN RFC, but the BSD implementation */
4354 /* requires that the client port be a priviliged port (<1024) */
4355 /* on a Unix system this would require SuperUser permissions */
4356 /* thereby saying that the root of the Unix system has given */
4357 /* permission for this connection to be created */
4358 if (service->s_port == htons((unsigned short)RLOGIN_PORT)) {
4359 static unsigned short lport = 1024; /* max reserved port */
4360 #ifdef OS2
4361 int s_errno;
4362 #endif /* OS2 */
4363
4364 lport--; /* Make sure we do not reuse a port */
4365 if (lport == 512)
4366 lport = 1023;
4367
4368 sin.sin_family = AF_INET;
4369 if (tcp_address) {
4370 #ifdef INADDRX
4371 inaddrx = inet_addr(tcp_address);
4372 sin.sin_addr.s_addr = *(unsigned long *)&inaddrx;
4373 #else
4374 sin.sin_addr.s_addr = inet_addr(tcp_address);
4375 #endif /* INADDRX */
4376 } else
4377 sin.sin_addr.s_addr = INADDR_ANY;
4378 while (1) {
4379 sin.sin_port = htons(lport);
4380 if (bind(ttyfd, (struct sockaddr *)&sin, sizeof(sin)) >= 0)
4381 break;
4382 #ifdef OS2
4383 s_errno = socket_errno;
4384 if (s_errno && /* OS2 bind fails with 0, if already in use */
4385 #ifdef NT
4386 s_errno != WSAEADDRINUSE
4387 #else
4388 s_errno != SOCEADDRINUSE &&
4389 s_errno != (SOCEADDRINUSE - SOCBASEERR)
4390 #endif /* NT */
4391 )
4392 #else /* OS2 */
4393 #ifdef TGVORWIN
4394 if (socket_errno != EADDRINUSE)
4395 #else
4396 if (errno != EADDRINUSE)
4397 #endif /* TGVORWIN */
4398 #endif /* OS2 */
4399 {
4400 #ifdef COMMENT
4401 printf("\nBind failed with errno %d for port %d.\n",
4402 #ifdef OS2
4403 s_errno
4404 #else
4405 #ifdef TGVORWIN
4406 socket_errno
4407 #else
4408 errno
4409 #endif /* TGVORWIN */
4410 #endif /* OS2 */
4411 , lport
4412 );
4413 #ifdef OS2
4414 debug(F101,"rlogin bind failed","",s_errno);
4415 #else
4416 #ifdef TGVORWIN
4417 debug(F101,"rlogin bind failed","",socket_errno);
4418 #ifdef OLD_TWG
4419 errno = socket_errno;
4420 #endif /* OLD_TWG */
4421 socket_perror("rlogin bind");
4422 #else
4423 debug(F101,"rlogin bind failed","",errno);
4424 perror("rlogin bind");
4425 #endif /* TGVORWIN */
4426 #endif /* OS2 */
4427 #else /* COMMENT */
4428 #ifdef OS2
4429 debug(F101,"rlogin bind s_errno","",s_errno);
4430 perror("rlogin bind");
4431 #else
4432 #ifdef VMS
4433 printf("\r\n"); /* complete any previous message */
4434 #endif /* VMS */
4435 #ifdef TGVORWIN
4436 debug(F101,"rlogin bind socket_errno","",socket_errno);
4437 #ifdef OLD_TWG
4438 errno = socket_errno;
4439 #endif /* OLD_TWG */
4440 socket_perror("rlogin bind");
4441 #else
4442 debug(F101,"rlogin bind errno","",errno);
4443 perror("rlogin bind");
4444 #endif /* TGVORWIN */
4445 #endif /* OS2 */
4446 debug(F101,"rlogin local port","",lport);
4447 #endif /* COMMENT */
4448 netclos();
4449 return -1;
4450 }
4451 lport--;
4452 if (lport == 512 /* lowest reserved port to use */ ) {
4453 printf("\nNo reserved ports available.\n");
4454 netclos();
4455 return -1;
4456 }
4457 }
4458 debug(F101,"rlogin lport","",lport);
4459 ttnproto = NP_RLOGIN;
4460 } else
4461 #endif /* RLOGCODE */
4462
4463 /* If a specific TCP address on the local host is desired we */
4464 /* must bind it to the socket. */
4465 #ifndef datageneral
4466 if (tcp_address) {
4467 int s_errno;
4468
4469 debug(F110,"netopen binding socket to",tcp_address,0);
4470 bzero((char *)&sin,sizeof(sin));
4471 sin.sin_family = AF_INET;
4472 #ifdef INADDRX
4473 inaddrx = inet_addr(tcp_address);
4474 sin.sin_addr.s_addr = *(unsigned long *)&inaddrx;
4475 #else
4476 sin.sin_addr.s_addr = inet_addr(tcp_address);
4477 #endif /* INADDRX */
4478 sin.sin_port = 0;
4479 if (bind(ttyfd, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
4480 s_errno = socket_errno; /* Save error code */
4481 #ifdef TCPIPLIB
4482 socket_close(ttyfd);
4483 #else /* TCPIPLIB */
4484 close(ttyfd);
4485 #endif /* TCPIPLIB */
4486 ttyfd = -1;
4487 wasclosed = 1;
4488 errno = s_errno; /* and report this error */
4489 debug(F101,"netopen bind errno","",errno);
4490 return(-1);
4491 }
4492 }
4493 #endif /* datageneral */
4494
4495 /* Now connect to the socket on the other end. */
4496
4497 #ifdef EXCELAN
4498 if (connect(ttyfd, &r_addr) < 0)
4499 #else
4500 #ifdef NT
4501 WSASafeToCancel = 1;
4502 #endif /* NT */
4503 if (connect(ttyfd, (struct sockaddr *)&r_addr, sizeof(r_addr)) < 0)
4504 #endif /* EXCELAN */
4505 {
4506 #ifdef NT
4507 WSASafeToCancel = 0;
4508 #endif /* NT */
4509 #ifdef OS2
4510 i = socket_errno;
4511 #else /* OS2 */
4512 #ifdef TGVORWIN
4513 i = socket_errno;
4514 #else
4515 i = errno; /* Save error code */
4516 #endif /* TGVORWIN */
4517 #endif /* OS2 */
4518 #ifdef RLOGCODE
4519 if (
4520 #ifdef OS2
4521 i && /* OS2 bind fails with 0, if already in use */
4522 #ifdef NT
4523 i == WSAEADDRINUSE
4524 #else
4525 (i == SOCEADDRINUSE ||
4526 i == (SOCEADDRINUSE - SOCBASEERR))
4527 #endif /* NT */
4528 #else /* OS2 */
4529 #ifdef TGVORWIN
4530 socket_errno == EADDRINUSE
4531 #else
4532 errno == EADDRINUSE
4533 #endif /* TGVORWIN */
4534 #endif /* OS2 */
4535 && ttnproto == NP_RLOGIN) {
4536 #ifdef TCPIPLIB
4537 socket_close(ttyfd); /* Close it. */
4538 #else
4539 close(ttyfd);
4540 #endif /* TCPIPLIB */
4541 continue; /* Try a different lport */
4542 }
4543 #endif /* RLOGCODE */
4544 #ifdef HADDRLIST
4545 #ifdef h_addr
4546 if (host && host->h_addr_list && host->h_addr_list[1]) {
4547 perror("");
4548 host->h_addr_list++;
4549 bcopy(host->h_addr_list[0],
4550 (caddr_t)&r_addr.sin_addr,
4551 host->h_length);
4552
4553 ckstrncpy(ipaddr,(char *)inet_ntoa(r_addr.sin_addr),20);
4554 debug(F110,"netopen h_addr_list",ipaddr,0);
4555 if (!quiet && *ipaddr) {
4556 printf(" Trying %s... ", ipaddr);
4557 fflush(stdout);
4558 }
4559 #ifdef TCPIPLIB
4560 socket_close(ttyfd); /* Close it. */
4561 #else
4562 close(ttyfd);
4563 #endif /* TCPIPLIB */
4564 continue;
4565 }
4566 #endif /* h_addr */
4567 #endif /* HADDRLIST */
4568 netclos();
4569 ttyfd = -1;
4570 wasclosed = 1;
4571 ttnproto = NP_NONE;
4572 errno = i; /* And report this error */
4573 #ifdef EXCELAN
4574 if (errno) experror("netopen connect");
4575 #else
4576 #ifdef TGVORWIN
4577 debug(F101,"netopen connect error","",socket_errno);
4578 /* if (errno) socket_perror("netopen connect"); */
4579 #ifdef OLD_TWG
4580 errno = socket_errno;
4581 #endif /* OLD_TWG */
4582 if (!quiet)
4583 socket_perror("netopen connect");
4584 #else /* TGVORWIN */
4585 debug(F101,"netopen connect errno","",errno);
4586 #ifdef VMS
4587 if (!quiet)
4588 perror("\r\nFailed");
4589 #else
4590 if (!quiet)
4591 perror("Failed");
4592 #endif /* VMS */
4593 #ifdef DEC_TCPIP
4594 if (!quiet)
4595 perror("netopen connect");
4596 #endif /* DEC_TCPIP */
4597 #ifdef CMU_TCPIP
4598 if (!quiet)
4599 perror("netopen connect");
4600 #endif /* CMU_TCPIP */
4601 #endif /* TGVORWIN */
4602 #endif /* EXCELAN */
4603 return(-1);
4604 }
4605 #ifdef NT
4606 WSASafeToCancel = 0;
4607 #endif /* NT */
4608 isconnect = 1;
4609 } while (!isconnect);
4610
4611 #ifdef NON_BLOCK_IO
4612 on = 1;
4613 x = socket_ioctl(ttyfd,FIONBIO,&on);
4614 debug(F101,"netopen FIONBIO","",x);
4615 #endif /* NON_BLOCK_IO */
4616
4617 #ifdef NT_TCP_OVERLAPPED
4618 OverlappedWriteInit();
4619 OverlappedReadInit();
4620 #endif /* NT_TCP_OVERLAPPED */
4621
4622 ttnet = nett; /* TCP/IP (sockets) network */
4623
4624 #ifndef NOHTTP
4625 /* We have succeeded in connecting to the HTTP PROXY. So now we */
4626 /* need to attempt to connect through the proxy to the actual host */
4627 /* If that is successful, we have to pretend that we made a direct */
4628 /* connection to the actual host. */
4629
4630 if ( tcp_http_proxy ) {
4631 #ifdef OS2
4632 char * agent = "Kermit 95"; /* Default user agent */
4633 #else
4634 char * agent = "C-Kermit";
4635 #endif /* OS2 */
4636
4637 if (http_connect(ttyfd,
4638 tcp_http_proxy_agent ? tcp_http_proxy_agent : agent,
4639 NULL,
4640 tcp_http_proxy_user,
4641 tcp_http_proxy_pwd,
4642 0,
4643 proxycopy
4644 ) < 0) {
4645 netclos();
4646 return(-1);
4647 }
4648
4649 ckstrncpy(namecopy,proxycopy,NAMECPYL);
4650 p = namecopy; /* Was a service requested? */
4651 while (*p != '\0' && *p != ':') p++; /* Look for colon */
4652 *p = '\0';
4653 }
4654 #endif /* NOHTTP */
4655
4656 /* Jeff - Does this next block of code that set's the protocol */
4657 /* need to be here anymore? 5/10/2000 */
4658
4659 /* There are certain magic port numbers that when used require */
4660 /* the use of specific protocols. Check this now before we */
4661 /* set the SO_OOBINLINE state or we might get it wrong. */
4662 x = ntohs((unsigned short)service->s_port);
4663 svcnum = x;
4664 /* See if the service is TELNET. */
4665 if (x == TELNET_PORT) {
4666 /* Yes, so if raw port not requested */
4667 #ifdef COMMENT
4668 /* Jeff 2005/12/30 */
4669 if (ttnproto != NP_TCPRAW && ttnproto != NP_SSL_RAW &&
4670 ttnproto != NP_TLS_RAW && ttnproto != NP_NONE)
4671 #else
4672 /* fdc 2005/12/04 */
4673 if (ttnproto != NP_TCPRAW && ttnproto != NP_NONE)
4674 #endif /* COMMENT */
4675 ttnproto = NP_TELNET; /* Select TELNET protocol. */
4676 }
4677 #ifdef RLOGCODE
4678 else if (x == RLOGIN_PORT) {
4679 ttnproto = NP_RLOGIN;
4680 }
4681 #ifdef CK_KERBEROS
4682 /* There is no good way to do this. If the user didn't tell */
4683 /* which one to use up front. We may guess wrong if the user */
4684 /* has both Kerberos versions installed and valid TGTs for each */
4685 else if (x == KLOGIN_PORT &&
4686 ttnproto != NP_K4LOGIN &&
4687 ttnproto != NP_K5LOGIN) {
4688 if (ck_krb5_is_installed() &&
4689 ck_krb5_is_tgt_valid())
4690 ttnproto = NP_K5LOGIN;
4691 else if (ck_krb4_is_installed() && ck_krb4_is_tgt_valid())
4692 ttnproto = NP_K4LOGIN;
4693 else
4694 ttnproto = NP_K4LOGIN;
4695 } else if (x == EKLOGIN_PORT &&
4696 ttnproto != NP_EK4LOGIN &&
4697 ttnproto != NP_EK5LOGIN) {
4698 if (ck_krb5_is_installed() && ck_krb5_is_tgt_valid())
4699 ttnproto = NP_EK5LOGIN;
4700 else if (ck_krb4_is_installed() && ck_krb4_is_tgt_valid())
4701 ttnproto = NP_EK4LOGIN;
4702 else
4703 ttnproto = NP_EK4LOGIN;
4704 }
4705 #endif /* CK_KERBEROS */
4706 #endif /* RLOGCODE */
4707 #ifdef IKS_OPTION
4708 else if (x == KERMIT_PORT) { /* IKS uses Telnet protocol */
4709 if (ttnproto == NP_NONE)
4710 ttnproto = NP_KERMIT;
4711 }
4712 #endif /* IKS_OPTION */
4713
4714 #ifdef SO_OOBINLINE
4715 /*
4716 The symbol SO_OOBINLINE is not known to Ultrix 2.0.
4717 It means "leave out of band data inline". The normal value is 0x0100,
4718 but don't try this on systems where the symbol is undefined.
4719 */
4720 /*
4721 Note from Jeff Altman: 12/13/95
4722 In implementing rlogin protocol I have come to the conclusion that it is
4723 a really bad idea to read out-of-band data inline.
4724 At least Windows and OS/2 does not handle this well.
4725 And if you need to know that data is out-of-band, then it becomes
4726 absolutely pointless.
4727
4728 Therefore, at least on OS2 and Windows (NT) I have changed the value of
4729 on to 0, so that out-of-band data stays out-of-band.
4730
4731 12/18/95
4732 Actually, OOB data should be read inline when possible. Especially with
4733 protocols that don't care about the Urgent flag. This is true with Telnet.
4734 With Rlogin, you need to be able to catch OOB data. However, the best
4735 way to do this is to set a signal handler on SIGURG. This isn't possible
4736 on OS/2 and Windows. But it is in UNIX. We will also need OOB data for
4737 FTP so better create a general mechanism.
4738
4739 The reason for making OOB data be inline is that the standard ttinc/ttoc
4740 calls can be used for reading that data on UNIX systems. If we didn't
4741 have the OOBINLINE option set then we would have to use recv(,MSG_OOB)
4742 to read it.
4743 */
4744 #ifdef RLOGCODE
4745 #ifdef TCPIPLIB
4746 if (ttnproto == NP_RLOGIN
4747 #ifdef CK_KERBEROS
4748 || ttnproto == NP_K4LOGIN || ttnproto == NP_EK4LOGIN
4749 || ttnproto == NP_K5LOGIN || ttnproto == NP_EK5LOGIN
4750 #endif /* CK_KERBEROS */
4751 )
4752 on = 0;
4753 #else /* TCPIPLIB */
4754 if (ttnproto == NP_RLOGIN
4755 #ifdef CK_KERBEROS
4756 || ttnproto == NP_K4LOGIN || ttnproto == NP_EK4LOGIN
4757 || ttnproto == NP_K5LOGIN || ttnproto == NP_EK5LOGIN
4758 #endif /* CK_KERBEROS */
4759 ) {
4760 debug(F100,"Installing rlogoobh on SIGURG","",0);
4761 signal(SIGURG, rlogoobh);
4762 on = 0;
4763 } else {
4764 debug(F100,"Ignoring SIGURG","",0);
4765 signal(SIGURG, SIG_DFL);
4766 }
4767 #endif /* TCPIPLIB */
4768 #endif /* RLOGCODE */
4769
4770 #ifdef datageneral
4771 setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
4772 #else
4773 #ifdef BSD43
4774 setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
4775 #else
4776 #ifdef OSF1
4777 setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
4778 #else
4779 #ifdef POSIX
4780 setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
4781 #else
4782 #ifdef MOTSV88R4
4783 setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
4784 #else
4785 #ifdef SOLARIS
4786 /*
4787 Maybe this applies to all SVR4 versions, but the other (else) way has been
4788 compiling and working fine on all the others, so best not to change it.
4789 */
4790 setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
4791 #else
4792 #ifdef OSK
4793 setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
4794 #else
4795 #ifdef OS2
4796 {
4797 int rc;
4798 rc = setsockopt(ttyfd,
4799 SOL_SOCKET,
4800 SO_OOBINLINE,
4801 (char *) &on,
4802 sizeof on
4803 );
4804 debug(F111,"setsockopt SO_OOBINLINE",on ? "on" : "off" ,rc);
4805 }
4806 #else
4807 #ifdef VMS /* or, at least, VMS with gcc */
4808 setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
4809 #else
4810 #ifdef CLIX
4811 setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
4812 #else
4813 setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE, &on, sizeof on);
4814 #endif /* CLIX */
4815 #endif /* VMS */
4816 #endif /* OS2 */
4817 #endif /* OSK */
4818 #endif /* SOLARIS */
4819 #endif /* MOTSV88R4 */
4820 #endif /* POSIX */
4821 #endif /* BSD43 */
4822 #endif /* OSF1 */
4823 #endif /* datageneral */
4824 #endif /* SO_OOBINLINE */
4825
4826 #ifndef NOTCPOPTS
4827 #ifndef datageneral
4828 #ifdef SOL_SOCKET
4829 #ifdef TCP_NODELAY
4830 no_delay(ttyfd,tcp_nodelay);
4831 #endif /* TCP_NODELAY */
4832 #ifdef SO_KEEPALIVE
4833 keepalive(ttyfd,tcp_keepalive);
4834 #endif /* SO_KEEPALIVE */
4835 #ifdef SO_LINGER
4836 ck_linger(ttyfd,tcp_linger, tcp_linger_tmo);
4837 #endif /* SO_LINGER */
4838 #ifdef SO_SNDBUF
4839 sendbuf(ttyfd,tcp_sendbuf);
4840 #endif /* SO_SNDBUF */
4841 #ifdef SO_RCVBUF
4842 recvbuf(ttyfd,tcp_recvbuf);
4843 #endif /* SO_RCVBUF */
4844 #endif /* SOL_SOCKET */
4845 #endif /* datageneral */
4846 #endif /* NOTCPOPTS */
4847
4848 #ifndef datageneral
4849 /* Find out our own IP address. */
4850 /* We need the l_addr structure for [E]KLOGIN. */
4851 l_slen = sizeof(l_addr);
4852 bzero((char *)&l_addr, l_slen);
4853 #ifndef EXCELAN
4854 if (!getsockname(ttyfd, (struct sockaddr *)&l_addr, &l_slen)) {
4855 char * s = (char *)inet_ntoa(l_addr.sin_addr);
4856 ckstrncpy(myipaddr, s, 20);
4857 debug(F110,"getsockname",myipaddr,0);
4858 }
4859 #endif /* EXCELAN */
4860 #endif /* datageneral */
4861
4862 /*
4863 This is really only needed for Kerberos IV but is useful information in any
4864 case. If we connect to a name that is really a pool, we need to get the
4865 name of the machine we are actually connecting to for K4 to authenticate
4866 properly. This way we also update the names properly.
4867
4868 However, it is a security hole when used with insecure DNS.
4869
4870 Note: This does not work on Windows 95 or Windows NT 3.5x. This is because
4871 of the Microsoft implementation of gethostbyaddr() in both Winsock 1.1
4872 and Winsock 2.0 on those platforms. Their algorithm is:
4873
4874 1. Check the HOSTENT cache.
4875 2. Check the HOSTS file at %SystemRoot%\System32\DRIVERS\ETC.
4876 3. Do a DNS query if the DNS server is configured for name resolution.
4877 4. Do an additional NetBIOS remote adapter status to an IP address for its
4878 NetBIOS name table. This step is specific only to the Windows NT version
4879 3.51 implementation.
4880
4881 The problem is the use of the HOSTENT cache. It means that gethostbyaddr()
4882 can not be used to resolve the real name of machine if it was originally
4883 accessed by an alias used to represent a cluster.
4884 */
4885 if ((tcp_rdns && dns || tcp_rdns == SET_ON
4886 #ifdef CK_KERBEROS
4887 || tcp_rdns == SET_AUTO &&
4888 (ck_krb5_is_installed() || ck_krb4_is_installed())
4889 #endif /* CK_KERBEROS */
4890 )
4891 #ifndef NOHTTP
4892 && (tcp_http_proxy == NULL)
4893 #endif /* NOHTTP */
4894 #ifdef CK_SSL
4895 && !(ssl_only_flag || tls_only_flag)
4896 #endif /* CK_SSL */
4897 ) {
4898 #ifdef NT
4899 if (isWin95())
4900 sleep(1);
4901 #endif /* NT */
4902 if (!quiet) {
4903 printf(" Reverse DNS Lookup... ");
4904 fflush(stdout);
4905 }
4906 if (host = gethostbyaddr((char *)&r_addr.sin_addr,4,PF_INET)) {
4907 char * s;
4908 host = ck_copyhostent(host);
4909 debug(F100,"netopen gethostbyname != NULL","",0);
4910 if (!quiet) {
4911 printf("(OK)\n");
4912 fflush(stdout);
4913 }
4914 s = host->h_name;
4915 if (!s) { /* This can happen... */
4916 debug(F100,"netopen host->h_name is NULL","",0);
4917 s = "";
4918 }
4919 /* Something is wrong with inet_ntoa() on HPUX 10.xx */
4920 /* The compiler says "Integral value implicitly converted to */
4921 /* pointer in assignment." The prototype is right there */
4922 /* in <arpa/inet.h> so what's the problem? */
4923 /* Ditto in HP-UX 5.x, but not 8.x or 9.x... */
4924 if (!*s) { /* No name so substitute the address */
4925 debug(F100,"netopen host->h_name is empty","",0);
4926 s = inet_ntoa(r_addr.sin_addr); /* Convert address to string */
4927 if (!s) /* Trust No 1 */
4928 s = "";
4929 if (*s) { /* If it worked, use this string */
4930 ckstrncpy(ipaddr,s,20);
4931 }
4932 s = ipaddr; /* Otherwise stick with the IP */
4933 if (!*s) /* or failing that */
4934 s = namecopy; /* the name we were called with. */
4935 }
4936 if (*s) { /* Copying into our argument? */
4937 ckstrncpy(name,s,80); /* Bad Bad Bad */
4938 if ( (80-strlen(name)) > (strlen(svcbuf)+1) ) {
4939 ckstrncat(name,":",80-strlen(name));
4940 ckstrncat(name,svcbuf,80-strlen(name));
4941 }
4942 }
4943 if (!quiet && *s
4944 #ifndef NOICP
4945 && !doconx
4946 #endif /* NOICP */
4947 ) {
4948 printf(" %s connected on port %s\n",s,p);
4949 #ifdef BETADEBUG
4950 /* This is simply for testing the DNS entries */
4951 if (host->h_aliases) {
4952 char ** a = host->h_aliases;
4953 while (*a) {
4954 printf(" alias => %s\n",*a);
4955 a++;
4956 }
4957 }
4958 #endif /* BETADEBUG */
4959 }
4960 } else {
4961 if (!quiet) printf("Failed.\n");
4962 }
4963 } else if (!quiet) printf("(OK)\n");
4964 if (!quiet) fflush(stdout);
4965
4966 /* This should already have been done but just in case */
4967 ckstrncpy(ipaddr,(char *)inet_ntoa(r_addr.sin_addr),20);
4968
4969 #ifdef CK_SECURITY
4970
4971 /* Before Initialization Telnet/Rlogin Negotiations Init Kerberos */
4972 #ifndef NOHTTP
4973 if (tcp_http_proxy) {
4974 for (i=strlen(proxycopy); i >= 0 ; i--)
4975 if ( proxycopy[i] == ':' )
4976 proxycopy[i] = '\0';
4977 }
4978 #endif /* NOHTTP */
4979 ck_auth_init(
4980 #ifndef NOHTTP
4981 tcp_http_proxy ? proxycopy :
4982 #endif /* NOHTTP */
4983 (tcp_rdns && host && host->h_name && host->h_name[0]) ?
4984 (char *)host->h_name : (namecopy2[0] ? namecopy2 :
4985 (namecopy[0] ? namecopy : ipaddr)),
4986 ipaddr,
4987 uidbuf,
4988 ttyfd
4989 );
4990 #endif /* CK_SECURITY */
4991 #ifdef CK_SSL
4992 if (ck_ssleay_is_installed()) {
4993 if (!ssl_tn_init(SSL_CLIENT)) {
4994 debug(F100,"netopen ssl_tn_init() failed","",0);
4995 if (bio_err!=NULL) {
4996 BIO_printf(bio_err,"ssl_tn_init() failed\n");
4997 ERR_print_errors(bio_err);
4998 } else {
4999 fflush(stderr);
5000 fprintf(stderr,"ssl_tn_init() failed\n");
5001 ERR_print_errors_fp(stderr);
5002 }
5003 if (tls_only_flag || ssl_only_flag) {
5004 debug(F100,"netopen ssl/tls required","",0);
5005 netclos();
5006 return(-1);
5007 }
5008
5009 /* we will continue to accept the connection */
5010 /* without SSL or TLS support unless required. */
5011 if ( TELOPT_DEF_S_ME_MODE(TELOPT_START_TLS) != TN_NG_MU )
5012 TELOPT_DEF_S_ME_MODE(TELOPT_START_TLS) = TN_NG_RF;
5013 if ( TELOPT_DEF_S_U_MODE(TELOPT_START_TLS) != TN_NG_MU )
5014 TELOPT_DEF_S_U_MODE(TELOPT_START_TLS) = TN_NG_RF;
5015 if ( TELOPT_DEF_C_ME_MODE(TELOPT_START_TLS) != TN_NG_MU )
5016 TELOPT_DEF_C_ME_MODE(TELOPT_START_TLS) = TN_NG_RF;
5017 if ( TELOPT_DEF_C_U_MODE(TELOPT_START_TLS) != TN_NG_MU )
5018 TELOPT_DEF_C_U_MODE(TELOPT_START_TLS) = TN_NG_RF;
5019 } else if ( ck_ssl_outgoing(ttyfd) < 0 ) {
5020 debug(F100,"ck_ssl_outgoing() failed","",0);
5021 netclos();
5022 return(-1);
5023 }
5024 }
5025 #endif /* CK_SSL */
5026
5027 #ifdef RLOGCODE
5028 if (ttnproto == NP_RLOGIN
5029 #ifdef CK_KERBEROS
5030 || ttnproto == NP_K4LOGIN || ttnproto == NP_EK4LOGIN
5031 || ttnproto == NP_K5LOGIN || ttnproto == NP_EK5LOGIN
5032 #endif /* CK_KERBEROS */
5033 ) { /* Similar deal for rlogin */
5034 if (rlog_ini(((tcp_rdns && host && host->h_name && host->h_name[0]) ?
5035 (CHAR *)host->h_name : (CHAR *)ipaddr),
5036 service->s_port,
5037 &l_addr,&r_addr
5038 ) < 0) {
5039 debug(F100,"rlogin initialization failed","",0);
5040 netclos();
5041 return(-1);
5042 }
5043 } else
5044 #endif /* RLOGCODE */
5045 if (tn_ini() < 0) { /* Start Telnet negotiations. */
5046 netclos();
5047 return(-1); /* Gone, so open failed. */
5048 }
5049 if (ttchk() < 0) {
5050 netclos();
5051 return(-1);
5052 }
5053 #ifdef CK_KERBEROS
5054 #ifdef KRB5_U2U
5055 if ( ttnproto == NP_K5U2U ) {
5056 if (k5_user_to_user_client_auth()) {
5057 netclos();
5058 return(-1);
5059 }
5060 }
5061 #endif /* KRB5_U2U */
5062 #endif /* CK_KERBEROS */
5063
5064 debug(F101,"netopen service","",svcnum);
5065 debug(F110,"netopen name",name,0);
5066 debug(F110,"netopen ipaddr",ipaddr,0);
5067 ckstrncpy(hostipaddr,ipaddr,63);
5068
5069 if (lcl) if (*lcl < 0) /* Local mode. */
5070 *lcl = 1;
5071 #endif /* TCPSOCKET */
5072 return(0); /* Done. */
5073 }
5074
5075 /* N E T C L O S -- Close current network connection. */
5076
5077 #ifndef NOLOCAL
5078 _PROTOTYP(VOID slrestor,(VOID));
5079 #ifdef CK_SSL
5080 int tls_norestore = 0;
5081 #endif /* CK_SSL */
5082 #endif /* NOLOCAL */
5083
5084 int
netclos()5085 netclos() {
5086 static int close_in_progress = 0;
5087 int x = 0, y, z;
5088 debug(F101,"netclos","",ttyfd);
5089
5090 #ifdef NETLEBUF
5091 if (!tt_push_inited)
5092 le_init();
5093 #endif /* NETLEBUF */
5094
5095 if (ttyfd == -1) /* Was open? */
5096 return(0); /* Wasn't. */
5097
5098 if (close_in_progress)
5099 return(0);
5100 close_in_progress = 1; /* Remember */
5101
5102 #ifndef NOLOCAL
5103 /* This function call should not be here since this is a direct call */
5104 /* from an I/O routine to a user interface level function. However, */
5105 /* the reality is that we do not have pure interfaces. If we ever */
5106 /* decide to clean this up the UI level should assign this function */
5107 /* via a pointer assignment. - Jeff 9/10/1999 */
5108 #ifdef CK_SSL
5109 if (!tls_norestore)
5110 #endif /* CK_SSL */
5111 slrestor();
5112 #endif /* NOLOCAL */
5113 #ifdef OS2
5114 RequestTCPIPMutex(SEM_INDEFINITE_WAIT);
5115 #else /* OS2 */
5116 if (ttyfd > -1) /* Was. */
5117 #endif /* OS2 */
5118 {
5119 #ifdef VMS
5120 y = 1; /* Turn on nonblocking reads */
5121 z = socket_ioctl(ttyfd,FIONBIO,&y);
5122 debug(F111,"netclos FIONBIO","on",z);
5123 #endif /* VMS */
5124 #ifdef TNCODE
5125 if (ttnproto == NP_TELNET) {
5126 if (!TELOPT_ME(TELOPT_LOGOUT)
5127 #ifdef COMMENT
5128 /* Jeff 2005/12/30 */
5129 #ifdef CK_SSL
5130 && !ssl_raw_flag && !tls_raw_flag
5131 #endif /* CK_SSL */
5132 #endif /* COMMENT */
5133 ) {
5134 /* Send LOGOUT option before close */
5135 if (tn_sopt(DO,TELOPT_LOGOUT) >= 0) {
5136 TELOPT_UNANSWERED_DO(TELOPT_LOGOUT) = 1;
5137 /* It would be nice to call tn_wait but we can't */
5138 }
5139 }
5140 tn_push(); /* Place any waiting data into input*/
5141 }
5142 #endif /* TNCODE */
5143 #ifdef CK_SSL
5144 if (ssl_active_flag) {
5145 if (ssl_debug_flag)
5146 BIO_printf(bio_err,"calling SSL_shutdown\n");
5147 SSL_shutdown(ssl_con);
5148 ssl_active_flag = 0;
5149 }
5150 if (tls_active_flag) {
5151 if (ssl_debug_flag)
5152 BIO_printf(bio_err,"calling SSL_shutdown\n");
5153 SSL_shutdown(tls_con);
5154 tls_active_flag = 0;
5155 }
5156 #endif /* CK_SSL */
5157 #ifdef VMS
5158 ck_cancio(); /* Cancel any outstanding reads. */
5159 #endif /* VMS */
5160 #ifdef TCPIPLIB
5161 x = socket_close(ttyfd); /* Close it. */
5162 #else
5163 #ifndef OS2
5164 #ifdef IBMX25
5165 if (ttnet == NET_IX25) {
5166 /* riehm: should send a disc_req - but only if link is still OK */
5167 x = x25clear();
5168 close(ttyfd);
5169 if (x25serverfd) {
5170 /* we were the passive client of a server, now we
5171 * go back to being the normal client.
5172 * I hope that kermit can cope with the logic that
5173 * there can still be a connection after netclos
5174 * has been called.
5175 */
5176 ttyfd = x25serverfd;
5177 x25serverfd = 0;
5178 /*
5179 * need to close the server connection too - because
5180 * all file descriptors connected to the NPI have the
5181 * same status.
5182 *
5183 * The problem is that any waiting connections get
5184 * lost, the client doesn't realise, and hangs.
5185 */
5186 netclos();
5187 }
5188 x25_state = X25_CLOSED; /* riehm: dead code? */
5189 } else
5190 #endif /* IBMX25 */
5191 x = close(ttyfd);
5192 #endif /* OS2 */
5193 #endif /* TCPIPLIB */
5194 }
5195 ttyfd = -1; /* Mark it as closed. */
5196 wasclosed = 1;
5197 #ifdef OS2
5198 ReleaseTCPIPMutex();
5199 #endif /* OS2 */
5200 #ifdef TNCODE
5201 #ifdef CK_FORWARD_X
5202 fwdx_close_all(); /* Shut down any Forward X sockets */
5203 #endif /* CK_FORWARD_X */
5204 tn_reset(); /* The Reset Telnet Option table. */
5205 debug(F100,"netclose setting tn_init = 0","",0);
5206 tn_init = 0; /* Remember about telnet protocol... */
5207 sstelnet = 0; /* Client-side Telnet */
5208 #endif /* TNCODE */
5209 *ipaddr = '\0'; /* Zero the IP address string */
5210 tcp_incoming = 0; /* No longer incoming */
5211 /* Don't reset ttnproto so that we can remember which protocol is in use */
5212
5213 #ifdef TCPIPLIB
5214 /*
5215 Empty the internal buffers so they won't be used as invalid input on
5216 the next connect attempt (rlogin).
5217 */
5218 ttibp = 0;
5219 ttibn = 0;
5220 #endif /* TCPIPLIB */
5221 #ifdef CK_KERBEROS
5222 /* If we are automatically destroying Kerberos credentials on Close */
5223 /* do it now. */
5224 #ifdef KRB4
5225 if (krb4_autodel == KRB_DEL_CL) {
5226 extern struct krb_op_data krb_op;
5227 krb_op.version = 4;
5228 krb_op.cache = NULL;
5229 ck_krb4_destroy(&krb_op);
5230 }
5231 #endif /* KRB4 */
5232 #ifdef KRB5
5233 if (krb5_autodel == KRB_DEL_CL) {
5234 extern struct krb_op_data krb_op;
5235 extern char * krb5_d_cc;
5236 krb_op.version = 5;
5237 krb_op.cache = krb5_d_cc;
5238 ck_krb5_destroy(&krb_op);
5239 }
5240 #endif /* KRB5 */
5241 #endif /* CK_KERBEROS */
5242 close_in_progress = 0; /* Remember we are done. */
5243 return(x);
5244 }
5245
5246 #ifdef OS2
5247 int
os2socketerror(int s_errno)5248 os2socketerror( int s_errno ) {
5249 #ifdef OS2ONLY
5250 if (s_errno > 0 && s_errno <= SOCBASEERR) {
5251 /* in OS/2, there is a problem with threading in that
5252 * the value of errno is not thread safe. It can be
5253 * set to a value from a previous library call and if
5254 * it was not cleared it will appear here. Only treat
5255 * valid socket error codes as errors in this function.
5256 */
5257 debug(F100,"os2socketerror errno.h","",0);
5258 socket_errno = 0;
5259 return(0);
5260 }
5261 #endif /* OS2ONLY */
5262
5263 switch (s_errno) {
5264 case 0: /* NO ERROR */
5265 debug(F100,"os2socketerror NOERROR","",0);
5266 return(0);
5267 #ifdef NT
5268 case WSAECONNRESET:
5269 #else /* NT */
5270 case SOCECONNRESET:
5271 case SOCECONNRESET - SOCBASEERR:
5272 #endif /* NT */
5273 debug(F100,"os2socketerror ECONRESET","",0);
5274 tn_debug("ECONRESET");
5275 netclos(); /* *** *** */
5276 return(-1); /* Connection is broken. */
5277 #ifdef NT
5278 case WSAECONNABORTED:
5279 #else /* NT */
5280 case SOCECONNABORTED:
5281 case SOCECONNABORTED - SOCBASEERR:
5282 #endif /* NT */
5283 debug(F100,"os2socketerror ECONNABORTED","",0);
5284 tn_debug("ECONNABORTED");
5285 netclos(); /* *** *** */
5286 return(-1); /* Connection is broken. */
5287 #ifdef NT
5288 case WSAENETRESET:
5289 #else /* NT */
5290 case SOCENETRESET:
5291 case SOCENETRESET - SOCBASEERR:
5292 #endif /* NT */
5293 debug(F100,"os2socketerror ENETRESET","",0);
5294 tn_debug("ENETRESET");
5295 netclos(); /* *** *** */
5296 return(-1); /* Connection is broken. */
5297 #ifdef NT
5298 case WSAENOTCONN:
5299 #else /* NT */
5300 case SOCENOTCONN:
5301 case SOCENOTCONN - SOCBASEERR:
5302 #endif /* NT */
5303 debug(F100,"os2socketerror ENOTCONN","",0);
5304 tn_debug("ENOTCONN");
5305 netclos(); /* *** *** */
5306 return(-1); /* Connection is broken. */
5307 #ifdef NT
5308 case WSAESHUTDOWN:
5309 debug(F100,"os2socketerror ESHUTDOWN","",0);
5310 tn_debug("ESHUTDOWN");
5311 netclos(); /* *** *** */
5312 return(-1); /* Connection is broken. */
5313 #endif /* NT */
5314 #ifdef NT
5315 case WSAEWOULDBLOCK:
5316 #else
5317 case SOCEWOULDBLOCK:
5318 case SOCEWOULDBLOCK - SOCBASEERR:
5319 #endif /* NT */
5320 debug(F100,"os2socketerror EWOULDBLOCK","",0);
5321 return(0);
5322 #ifdef NT
5323 case ERROR_IO_INCOMPLETE:
5324 case ERROR_IO_PENDING:
5325 case ERROR_OPERATION_ABORTED:
5326 return(0);
5327 #endif /* NT */
5328 default:
5329 return(-2);
5330 }
5331 return(0);
5332 }
5333 #endif /* OS2 */
5334
5335 /* N E T T C H K -- Check if network up, and how many bytes can be read */
5336 /*
5337 Returns number of bytes waiting, or -1 if connection has been dropped.
5338 */
5339 int /* Check how many bytes are ready */
nettchk()5340 nettchk() { /* for reading from network */
5341 #ifdef TCPIPLIB
5342 long count = 0;
5343 int x = 0, z;
5344 long y;
5345 char c;
5346 int rc;
5347 #ifdef NT
5348 extern int ionoblock; /* For Overlapped I/O */
5349 #endif /* NT */
5350
5351 debug(F101,"nettchk entry ttibn","",ttibn);
5352 debug(F101,"nettchk entry ttibp","",ttibp);
5353
5354 #ifdef NETLEBUF
5355 {
5356 int n = 0;
5357 if (ttpush >= 0)
5358 n++;
5359 n += le_inbuf();
5360 if (n > 0)
5361 return(n);
5362 }
5363 #endif /* NETLEBUF */
5364
5365 #ifndef OS2
5366 #ifndef BEBOX
5367 socket_errno = 0; /* This is a function call in NT, and BeOS */
5368 #endif /* BEBOX */
5369 #endif /* OS2 */
5370
5371 if (ttyfd == -1) {
5372 debug(F100,"nettchk socket is closed","",0);
5373 return(-1);
5374 }
5375 /*
5376 Note: this socket_ioctl() call does NOT return an error if the
5377 connection has been broken. (At least not in MultiNet.)
5378 */
5379 #ifdef COMMENT
5380 /* Another trick that can be tried here is something like this: */
5381
5382 if (ttnet == NET_TCPB) {
5383 char dummy;
5384 x = read(ttyfd,&dummy,0); /* Try to read nothing */
5385 if (x < 0) { /* "Connection reset by peer" */
5386 perror("TCP/IP"); /* or somesuch... */
5387 ttclos(0); /* Close our end too. */
5388 return(-1);
5389 }
5390 }
5391 #endif /* COMMENT */
5392
5393
5394 #ifdef CK_SSL
5395 if (ssl_active_flag) {
5396 #ifndef IKSDONLY
5397 #ifdef OS2
5398 if ( IsConnectMode() ) {
5399 debug(F101,"nettchk (ssl_active_flag) returns","",count);
5400 return(0);
5401 }
5402 #endif /* OS2 */
5403 #endif /* IKSDONLY */
5404 count = SSL_pending(ssl_con);
5405 if (count < 0) {
5406 debug(F111,"nettchk","SSL_pending error",count);
5407 netclos();
5408 return(-1);
5409 }
5410 if ( count > 0 )
5411 return(count); /* Don't perform a read */
5412 } else if (tls_active_flag) {
5413 #ifndef IKSDONLY
5414 #ifdef OS2
5415 if ( IsConnectMode() ) {
5416 debug(F101,"nettchk (tls_active_flag) returns","",count);
5417 return(0);
5418 }
5419 #endif /* OS2 */
5420 #endif /* IKSDONLY */
5421 count = SSL_pending(tls_con);
5422 if (count < 0) {
5423 debug(F111,"nettchk","TLS_pending error",count);
5424 netclos();
5425 return(-1);
5426 }
5427 if ( count > 0 )
5428 return(count); /* Don't perform a read */
5429 } else
5430 #endif /* CK_SSL */
5431
5432 if (socket_ioctl(ttyfd,FIONREAD,
5433 #ifdef COMMENT
5434 /* Now we've changed the ioctl(..,..,x) prototype for DECC to (void *) */
5435 #ifdef __DECC
5436 /* NOTE: "&count" might need to be "(char *)&count" in some settings. */
5437 /* Cast needed for DECC 4.1 & later? */
5438 /* Maybe, but __DECC_VER only exists in 5.0 and later */
5439 (char *)
5440 #endif /* __DECC */
5441 #endif /* COMMENT */
5442 &count
5443 ) < 0) {
5444 debug(F101,"nettchk socket_ioctl error","",socket_errno);
5445 /* If the connection is gone, the connection is gone. */
5446 netclos();
5447 #ifdef NT_TCP_OVERLAPPED
5448 /* Is there anything in the overlapped I/O buffers? */
5449 count += OverlappedDataWaiting();
5450 #endif /* NT_TCP_OVERLAPPED */
5451 count += ttibn;
5452 return(count>0?count:-1);
5453 }
5454 debug(F101,"nettchk count","",count);
5455 #ifdef NT_TCP_OVERLAPPED
5456 /* Is there anything in the overlapped I/O buffers? */
5457 count += OverlappedDataWaiting();
5458 debug(F101,"nettchk count w/overlapped","",count);
5459 #endif /* NT_TCP_OVERLAPPED */
5460
5461 #ifdef OS2
5462 #ifndef IKSDONLY
5463 if ( IsConnectMode() ) {
5464 debug(F101,"nettchk (FIONREAD) returns","",count);
5465 return(count);
5466 }
5467 #endif /* IKSDONLY */
5468 #endif /* OS2 */
5469
5470 /* For the sake of efficiency, if there is still data in the ttibuf */
5471 /* do not go to the bother of checking to see of the connection is */
5472 /* still valid. The handle is still good, so just return the count */
5473 /* of the bytes that we already have left to process. */
5474 #ifdef OS2
5475 if ( count > 0 || ttibn > 0 ) {
5476 count+=ttibn;
5477 debug(F101,"nettchk (count+ttibn > 0) returns","",count);
5478 return(count);
5479 } else {
5480 RequestTCPIPMutex(SEM_INDEFINITE_WAIT);
5481 if ( ttibn == 0 )
5482 ttibp = 0; /* reset for next read */
5483 }
5484 #else /* OS2 */
5485 if ( count > 0 || ttibn > 0 ) {
5486 debug(F101,"nettchk returns","",count+ttibn);
5487 return(count+ttibn);
5488 }
5489 ttibn = ttibp = 0;
5490 #endif /* OS2 */
5491
5492 /*
5493 The following code works well in most settings, but messes things up in
5494 others, including CMU/Tek TCP/IP and UCX 2.0, where it somehow manages to
5495 make it impossible to ever make a new connection to the same host again with
5496 CONNECT, once it has been logged out from the first time. Not even if you
5497 HANGUP first, or SET HOST<CR>, or SET LINE<CR>. Reportedly, however, it
5498 does work OK in later releases of UCX. But there is no way we can
5499 accommodate both old and new -- we might have static linking or dynamic
5500 linking, etc etc. If we have static, I only have access to 2.0, where this
5501 doesn't work, etc etc blah blah.
5502
5503 In the following lines, we define a symbol NOCOUNT for builds where we want
5504 to omit this code. By default, it is omitted for CMU/Tek. You can force
5505 omission of it for other combinations by defining NOCOUNT in CFLAGS. You
5506 can force inclusion of this code, even for CMU/Tek, by including NONOCOUNT
5507 in CFLAGS.
5508 */
5509 #ifdef NONOCOUNT
5510 #ifdef NOCOUNT
5511 #undef NOCOUNT
5512 #endif /* NOCOUNT */
5513 #else
5514 #ifndef NOCOUNT
5515 #ifdef CMU_TCPIP
5516 #define NOCOUNT
5517 #endif /* CMU_TCPIP */
5518 #endif /* NOCOUNT */
5519 #endif /* NONOCOUNT */
5520
5521
5522 /* From this point forward we have a possible race condition in K95
5523 * due to its use of multiple threads. Therefore, we must ensure
5524 * that only one thread attempt to read/write from the socket at a
5525 * time. Otherwise, it is possible for a buffer to be overwritten.
5526 */
5527 /* we know now that count >= 0 and that ttibn == 0 */
5528
5529 if (count == 0
5530 #ifdef RLOGCODE
5531 #ifdef CK_KERBEROS
5532 && ttnproto != NP_EK4LOGIN && ttnproto != NP_EK5LOGIN
5533 #endif /* CK_KERBEROS */
5534 #endif /* RLOGCODE */
5535 ) {
5536 int s_errno = 0;
5537 #ifndef NOCOUNT
5538 /*
5539 Here we need to tell the difference between a 0 count on an active
5540 connection, and a 0 count because the remote end of the socket broke the
5541 connection. There is no mechanism in TGV MultiNet (or WIN/TCP?) to query
5542 the status of the connection, so we have to do a read. -1 means there was
5543 no data available (socket_errno == EWOULDBLOCK), 0 means the connection is
5544 down. But if, by chance, we actually get a character, we have to put it
5545 where it won't be lost.
5546 */
5547 #ifndef NON_BLOCK_IO
5548 #ifdef OS2
5549 #ifdef CK_SSL
5550 RequestSSLMutex(SEM_INDEFINITE_WAIT);
5551 #endif /* CK_SSL */
5552 #endif /* OS2 */
5553 y = 1; /* Turn on nonblocking reads */
5554 z = socket_ioctl(ttyfd,FIONBIO,&y);
5555 debug(F111,"nettchk FIONBIO","on",z);
5556 #ifdef OS2
5557 #ifdef CK_SSL
5558 ReleaseSSLMutex();
5559 #endif /* CK_SSL */
5560 #endif /* OS2 */
5561 #endif /* NON_BLOCK_IO */
5562 #ifdef NT_TCP_OVERLAPPED
5563 ionoblock = 1; /* For Overlapped I/O */
5564 #endif /* NT_TCP_OVERLAPPED */
5565 #ifdef CK_SSL
5566 if ( ssl_active_flag || tls_active_flag ) {
5567 #ifdef OS2
5568 ssl_read:
5569 x = SSL_read( ssl_active_flag?ssl_con:tls_con,
5570 &ttibuf[ttibp+ttibn],
5571 TTIBUFL-ttibp-ttibn );
5572 switch (SSL_get_error(ssl_active_flag?ssl_con:tls_con,x)) {
5573 case SSL_ERROR_NONE:
5574 debug(F111,"nettchk SSL_ERROR_NONE","x",x);
5575 break;
5576 case SSL_ERROR_WANT_WRITE:
5577 debug(F100,"nettchk SSL_ERROR_WANT_WRITE","",0);
5578 x = -1;
5579 break;
5580 case SSL_ERROR_WANT_READ:
5581 debug(F100,"nettchk SSL_ERROR_WANT_READ","",0);
5582 x = -1;
5583 break;
5584 case SSL_ERROR_SYSCALL:
5585 if ( x == 0 ) { /* EOF */
5586 netclos();
5587 rc = -1;
5588 goto nettchk_return;
5589 } else {
5590 #ifdef NT
5591 int gle = GetLastError();
5592 #endif /* NT */
5593 #ifndef NON_BLOCK_IO
5594 #ifdef OS2
5595 #ifdef CK_SSL
5596 RequestSSLMutex(SEM_INDEFINITE_WAIT);
5597 #endif /* CK_SSL */
5598 #endif /* OS2 */
5599 y = 0; /* Turn off nonblocking reads */
5600 z = socket_ioctl(ttyfd,FIONBIO,&y);
5601 debug(F111,"nettchk FIONBIO","off",z);
5602 #ifdef OS2
5603 #ifdef CK_SSL
5604 ReleaseSSLMutex();
5605 #endif /* CK_SSL */
5606 #endif /* OS2 */
5607 #endif /* NON_BLOCK_IO */
5608 #ifdef NT_TCP_OVERLAPPED
5609 ionoblock = 0; /* For Overlapped I/O */
5610 #endif /* NT_TCP_OVERLAPPED */
5611 #ifdef NT
5612 debug(F111,"nettchk SSL_ERROR_SYSCALL",
5613 "GetLastError()",gle);
5614 rc = os2socketerror(gle);
5615 if (rc == -1)
5616 rc = -2;
5617 else if ( rc == -2 )
5618 rc = -1;
5619 goto nettchk_return;
5620 #endif /* NT */
5621 break;
5622 }
5623 case SSL_ERROR_WANT_X509_LOOKUP:
5624 debug(F100,"nettchk SSL_ERROR_WANT_X509_LOOKUP","",0);
5625 break;
5626 case SSL_ERROR_SSL:
5627 if (bio_err!=NULL) {
5628 int len;
5629 extern char ssl_err[];
5630 BIO_printf(bio_err,"nettchk() SSL_ERROR_SSL\n");
5631 ERR_print_errors(bio_err);
5632 len = BIO_read(bio_err,ssl_err,SSL_ERR_BFSZ);
5633 ssl_err[len < SSL_ERR_BFSZ ? len : SSL_ERR_BFSZ] = '\0';
5634 debug(F110,"nettchk SSL_ERROR_SSL",ssl_err,0);
5635 if (ssl_debug_flag)
5636 printf(ssl_err);
5637 } else if (ssl_debug_flag) {
5638 debug(F100,"nettchk SSL_ERROR_SSL","",0);
5639 fflush(stderr);
5640 fprintf(stderr,"nettchk() SSL_ERROR_SSL\n");
5641 ERR_print_errors_fp(stderr);
5642 }
5643 #ifdef COMMENT
5644 netclos();
5645 rc = -1;
5646 goto nettchk_return;
5647 #else
5648 x = -1;
5649 break;
5650 #endif
5651 case SSL_ERROR_ZERO_RETURN:
5652 debug(F100,"nettchk SSL_ERROR_ZERO_RETURN","",0);
5653 netclos();
5654 rc = -1;
5655 goto nettchk_return;
5656 default:
5657 debug(F100,"nettchk SSL_ERROR_?????","",0);
5658 netclos();
5659 rc = -1;
5660 goto nettchk_return;
5661 }
5662 #else /* OS2 */
5663 /* Do not block */
5664 x = -1;
5665 #endif /* OS2 */
5666 } else
5667 #endif /* CK_SSL */
5668 {
5669 #ifdef OS2
5670 x = socket_read(ttyfd,&ttibuf[ttibp+ttibn],
5671 TTIBUFL-ttibp-ttibn); /* Returns -1 if no data */
5672 #else /* OS2 */
5673 x = socket_read(ttyfd,&c,1); /* Returns -1 if no data */
5674 #endif /* OS2 */
5675 }
5676 s_errno = socket_errno; /* socket_errno may be a function */
5677 debug(F101,"nettchk socket_read","",x);
5678
5679 #ifndef NON_BLOCK_IO
5680 #ifdef OS2
5681 #ifdef CK_SSL
5682 RequestSSLMutex(SEM_INDEFINITE_WAIT);
5683 #endif /* CK_SSL */
5684 #endif /* OS2 */
5685 y = 0; /* Turn off nonblocking reads */
5686 z = socket_ioctl(ttyfd,FIONBIO,&y);
5687 debug(F111,"nettchk FIONBIO","off",z);
5688 #ifdef OS2
5689 #ifdef CK_SSL
5690 ReleaseSSLMutex();
5691 #endif /* CK_SSL */
5692 #endif /* OS2 */
5693 #endif /* NON_BLOCK_IO */
5694 #ifdef NT_TCP_OVERLAPPED
5695 ionoblock = 0; /* For Overlapped I/O */
5696 #endif /* NT_TCP_OVERLAPPED */
5697
5698 if (x == -1) {
5699 debug(F101,"nettchk socket_read errno","",s_errno);
5700 #ifdef OS2
5701 if (os2socketerror(s_errno) < 0) {
5702 rc = -1;
5703 goto nettchk_return;
5704 }
5705 #endif /* OS2 */
5706 } else if (x == 0) {
5707 debug(F100,"nettchk connection closed","",0);
5708 netclos(); /* *** *** */
5709 rc = -1;
5710 goto nettchk_return;
5711 }
5712 if (x >= 1) { /* Oops, actually got a byte? */
5713 #ifdef OS2
5714 /* In OS/2 we read directly into ttibuf[] */
5715 ckhexdump("nettchk got real data",&ttibuf[ttibp+ttibn],x);
5716 ttibn += x;
5717 #else /* OS2 */
5718 #ifdef CK_SSL
5719 if ( ssl_active_flag || tls_active_flag ) {
5720 ckhexdump("nettchk got real data",&ttibuf[ttibp+ttibn],x);
5721 ttibn += x;
5722 } else
5723 #endif /* CK_SSL */
5724 {
5725 debug(F101,"nettchk socket_read char","",c);
5726 debug(F101,"nettchk ttibp","",ttibp);
5727 debug(F101,"nettchk ttibn","",ttibn);
5728 /*
5729 In the case of Overlapped I/O the character would have come from
5730 the beginning of the buffer, so put it back.
5731 */
5732 if (ttibp > 0) {
5733 ttibp--;
5734 ttibuf[ttibp] = c;
5735 ttibn++;
5736 } else {
5737 ttibuf[ttibp+ttibn] = c;
5738 ttibn++;
5739 }
5740 }
5741 #endif /* OS2 */
5742 }
5743 #else /* NOCOUNT */
5744 if (ttnet == NET_TCPB) {
5745 char dummy;
5746 x = read(ttyfd,&dummy,0); /* Try to read nothing */
5747 if (x < 0) { /* "Connection reset by peer" */
5748 perror("TCP/IP"); /* or somesuch... */
5749 ttclos(0); /* Close our end too. */
5750 rc = -1;
5751 goto nettchk_return;
5752 }
5753 }
5754 #endif /* NOCOUNT */
5755 }
5756 #ifdef CK_KERBEROS
5757 #ifdef KRB4
5758 #ifdef RLOGCODE
5759 if (ttnproto == NP_EK4LOGIN)
5760 count += krb4_des_avail(ttyfd);
5761 #endif /* RLOGCODE */
5762 #endif /* KRB4 */
5763 #ifdef KRB5
5764 #ifdef RLOGCODE
5765 if (ttnproto == NP_EK5LOGIN)
5766 count += krb5_des_avail(ttyfd);
5767 #endif /* RLOGCODE */
5768 #ifdef KRB5_U2U
5769 if (ttnproto == NP_K5U2U)
5770 count += krb5_u2u_avail(ttyfd);
5771 #endif /* KRB5_U2U */
5772 #endif /* KRB5 */
5773 #endif /* CK_KERBEROS */
5774
5775 debug(F101,"nettchk returns","",count+ttibn);
5776 rc = count + ttibn;
5777
5778 nettchk_return:
5779 #ifdef OS2
5780 ReleaseTCPIPMutex();
5781 #endif /* OS2 */
5782 return(rc);
5783
5784 #else /* Not TCPIPLIB */
5785 /*
5786 UNIX just uses ttchk(), in which the ioctl() calls on the file descriptor
5787 seem to work OK.
5788 */
5789 return(ttchk());
5790 #endif /* TCPIPLIB */
5791 /*
5792 But what about X.25?
5793 */
5794 }
5795
5796 #ifndef OS2
5797 VOID
nettout(i)5798 nettout(i) int i; { /* Catch the alarm interrupts */
5799 debug(F100,"nettout caught timeout","",0);
5800 ttimoff();
5801 cklongjmp(njbuf, -1);
5802 }
5803 #endif /* !OS2 */
5804
5805 #ifdef TCPIPLIB
5806
5807 VOID
5808 #ifdef CK_ANSIC
donetinc(void * threadinfo)5809 donetinc(void * threadinfo)
5810 #else /* CK_ANSIC */
5811 donetinc(threadinfo) VOID * threadinfo;
5812 #endif /* CK_ANSIC */
5813 /* donetinc */ {
5814 #ifdef NTSIG
5815 extern int TlsIndex;
5816 setint();
5817 if (threadinfo) { /* Thread local storage... */
5818 TlsSetValue(TlsIndex,threadinfo);
5819 }
5820 #endif /* NTSIG */
5821 #ifdef CK_LOGIN
5822 #ifdef NT
5823 #ifdef IKSD
5824 if (inserver)
5825 setntcreds();
5826 #endif /* IKSD */
5827 #endif /* NT */
5828 #endif /* CK_LOGIN */
5829 while (1) {
5830 if (ttbufr() < 0) /* Keep trying to refill it. */
5831 break; /* Till we get an error. */
5832 if (ttibn > 0) /* Or we get a character. */
5833 break;
5834 }
5835 }
5836 #endif /* TCPIPLIB */
5837
5838 VOID
5839 #ifdef CK_ANSIC
failnetinc(void * threadinfo)5840 failnetinc(void * threadinfo)
5841 #else /* CK_ANSIC */
5842 failnetinc(threadinfo) VOID * threadinfo;
5843 #endif /* CK_ANSIC */
5844 /* failnetinc */ {
5845 ; /* Nothing to do on an error */
5846 }
5847
5848 /* N E T X I N -- Input block of characters from network */
5849
5850 int
netxin(n,buf)5851 netxin(n,buf) int n; CHAR * buf; {
5852 int len, i, j;
5853 #ifdef TCPIPLIB
5854 int rc;
5855 #endif /* TCPIPLIB */
5856
5857 if (ttyfd == -1) {
5858 debug(F100,"netxin socket is closed","",0);
5859 return(-2);
5860 }
5861 #ifdef CK_KERBEROS
5862 #ifdef KRB4
5863 #ifdef RLOGCODE
5864 if (ttnproto == NP_EK4LOGIN) {
5865 if ((len = krb4_des_read(ttyfd,buf,n)) < 0)
5866 return(-1);
5867 else
5868 return(len);
5869 }
5870 #endif /* RLOGCODE */
5871 #endif /* KRB4 */
5872 #ifdef KRB5
5873 #ifdef RLOGCODE
5874 if (ttnproto == NP_EK5LOGIN) {
5875 if ((len = krb5_des_read(ttyfd,(char *)buf,n,0)) < 0)
5876 return(-1);
5877 else
5878 return(len);
5879 }
5880 #endif /* RLOGCODE */
5881 #ifdef KRB5_U2U
5882 if (ttnproto == NP_K5U2U) {
5883 if ((len = krb5_u2u_read(ttyfd,(char *)buf,n)) < 0)
5884 return(-1);
5885 else
5886 return(len);
5887 }
5888 #endif /* KRB5_U2U */
5889 #endif /* KRB5 */
5890 #endif /* CK_KERBEROS */
5891
5892 #ifdef TCPIPLIB
5893 #ifdef OS2
5894 RequestTCPIPMutex(SEM_INDEFINITE_WAIT);
5895 #endif /* OS2 */
5896 if (ttibn == 0)
5897 if ((rc = ttbufr()) <= 0) {
5898 #ifdef OS2
5899 ReleaseTCPIPMutex();
5900 #endif /* OS2 */
5901 return(rc);
5902 }
5903
5904 if (ttibn <= n) {
5905 len = ttibn;
5906 memcpy(buf,&ttibuf[ttibp],len); /* safe */
5907 ttibp += len;
5908 ttibn = 0;
5909 } else {
5910 memcpy(buf,&ttibuf[ttibp],n); /* safe */
5911 ttibp += n;
5912 ttibn -= n;
5913 len = n;
5914 }
5915 #ifdef OS2
5916 ReleaseTCPIPMutex();
5917 #endif /* OS2 */
5918 #else /* TCPIPLIB */
5919 for (i = 0; i < n; i++) {
5920 if ((j = netinc(0)) < 0) {
5921 if (j < -1)
5922 return(j);
5923 else
5924 break;
5925 }
5926 buf[i] = j;
5927 }
5928 len = i;
5929 #endif /* TCPIPLIB */
5930
5931 #ifdef COMMENT
5932 #ifdef CK_ENCRYPTION
5933 /* This would be great if it worked. But what if the buffer we read */
5934 /* contains a telnet negotiation that changes the state of the */
5935 /* encryption. If so, we would be either decrypting unencrypted text */
5936 /* or not decrypting encrypted text. So we must move this call to */
5937 /* all functions that call ttxin(). In OS2 that means os2_netxin() */
5938 /* where the Telnet Negotiations are handled. */
5939 if (u_encrypt)
5940 ck_tn_decrypt(buf,len);
5941 #endif /* CK_ENCRYPTION */
5942 #endif /* COMMENT */
5943
5944 return(len);
5945 }
5946
5947 /* N E T I N C -- Input character from network */
5948
5949 #ifdef NETLEBUF
5950 #define LEBUF
5951 #endif /* NETLEBUF */
5952 #ifdef TTLEBUF
5953 #define LEBUF
5954 #endif /* TTLEBUF */
5955 #ifndef LEBUF
5956 #ifdef OS2
5957 #define LEBUF
5958 #endif /* OS2 */
5959 #endif /* LEBUF */
5960
5961 int
netinc(timo)5962 netinc(timo) int timo; {
5963 #ifdef TCPIPLIB
5964 int x; unsigned char c; /* The locals. */
5965
5966 #ifdef NETLEBUF
5967 if (ttpush >= 0) {
5968 debug(F111,"netinc","ttpush",ttpush);
5969 c = ttpush;
5970 ttpush = -1;
5971 return(c);
5972 }
5973 if (le_data) {
5974 if (le_getchar((CHAR *)&c) > 0) {
5975 debug(F111,"netinc le_getchar","c",c);
5976 return(c);
5977 }
5978 }
5979 #endif /* NETLEBUF */
5980
5981 if (ttyfd == -1) {
5982 debug(F100,"netinc socket is closed","",0);
5983 return(-2);
5984 }
5985
5986 #ifdef CK_KERBEROS
5987 #ifdef KRB4
5988 #ifdef RLOGCODE
5989 if (ttnproto == NP_EK4LOGIN) {
5990 if ((x = krb4_des_read(ttyfd,&c,1)) == 0)
5991 return(-1);
5992 else if (x < 0)
5993 return(-2);
5994 else
5995 return(c);
5996 }
5997 #endif /* RLOGCODE */
5998 #endif /* KRB4 */
5999 #ifdef KRB5
6000 #ifdef RLOGCODE
6001 if (ttnproto == NP_EK5LOGIN) {
6002 if ((x = krb5_des_read(ttyfd,&c,1,0)) == 0)
6003 return(-1);
6004 else if (x < 0)
6005 return(-2);
6006 else
6007 return(c);
6008 }
6009 #endif /* RLOGCODE */
6010 #ifdef KRB5_U2U
6011 if (ttnproto == NP_K5U2U) {
6012 if ((x = krb5_u2u_read(ttyfd,&c,1)) == 0)
6013 return(-1);
6014 else if (x < 0)
6015 return(-2);
6016 else
6017 return(c);
6018 }
6019 #endif /* KRB5_U2U */
6020 #endif /* KRB5 */
6021 #endif /* CK_KERBEROS */
6022
6023 #ifdef OS2
6024 RequestTCPIPMutex(SEM_INDEFINITE_WAIT);
6025 #endif /* OS2 */
6026 if (ttibn > 0) { /* Something in internal buffer? */
6027 #ifdef COMMENT
6028 debug(F100,"netinc char in buf","",0); /* Yes. */
6029 #endif /* COMMENT */
6030 x = 0; /* Success. */
6031 } else { /* Else must read from network. */
6032 x = -1; /* Assume failure. */
6033 #ifdef DEBUG
6034 debug(F101,"netinc goes to net, timo","",timo);
6035 #endif /* DEBUG */
6036 #ifdef CK_SSL
6037 /*
6038 * In the case of OpenSSL, it is possible that there is still
6039 * data waiting in the SSL session buffers that has not yet
6040 * been read by Kermit. If this is the case we must process
6041 * it without calling select() because select() will not return
6042 * with an indication that there is data to be read from the
6043 * socket. If there is no data pending in the SSL session
6044 * buffers then fall through to the select() code and wait for
6045 * some data to arrive.
6046 */
6047 if (ssl_active_flag) {
6048 x = SSL_pending(ssl_con);
6049 if (x < 0) {
6050 debug(F111,"netinc","SSL_pending error",x);
6051 netclos();
6052 #ifdef OS2
6053 ReleaseTCPIPMutex();
6054 #endif /* OS2 */
6055 return(-1);
6056 } else if ( x > 0 ) {
6057 if ( ttbufr() >= 0 ) {
6058 x = netinc(timo);
6059 #ifdef OS2
6060 ReleaseTCPIPMutex();
6061 #endif /* OS2 */
6062 return(x);
6063 }
6064 }
6065 x = -1;
6066 } else if (tls_active_flag) {
6067 x = SSL_pending(tls_con);
6068 if (x < 0) {
6069 debug(F111,"netinc","TLS_pending error",x);
6070 netclos();
6071 #ifdef OS2
6072 ReleaseTCPIPMutex();
6073 #endif /* OS2 */
6074 return(-1);
6075 } else if ( x > 0 ) {
6076 if ( ttbufr() >= 0 ) {
6077 x = netinc(timo);
6078 #ifdef OS2
6079 ReleaseTCPIPMutex();
6080 #endif /* OS2 */
6081 return(x);
6082 }
6083 }
6084 x = -1;
6085 }
6086 #endif /* CK_SSL */
6087 #ifndef LEBUF
6088 if (timo == 0) { /* Untimed case. */
6089 while (1) { /* Wait forever if necessary. */
6090 if (ttbufr() < 0) /* Refill buffer. */
6091 break; /* Error, fail. */
6092 if (ttibn > 0) { /* Success. */
6093 x = 0;
6094 break;
6095 }
6096 }
6097 } else /* Timed case... */
6098 #endif /* LEBUF */
6099 {
6100 #ifdef NT_TCP_OVERLAPPED
6101 /* This code is for use on NT when we are using */
6102 /* Overlapped I/O to handle reads. In the case */
6103 /* of outstanding reads select() doesn't work */
6104
6105 if (WaitForOverlappedReadData(timo)) {
6106 while (1) {
6107 if (ttbufr() < 0) /* Keep trying to refill it. */
6108 break; /* Till we get an error. */
6109 if (ttibn > 0) { /* Or we get a character. */
6110 x = 0;
6111 break;
6112 }
6113 }
6114 }
6115 #else /* NT_TCP_OVERLAPPED */
6116 #ifdef BSDSELECT
6117 fd_set rfds;
6118 struct timeval tv;
6119 int timeout = timo < 0 ? -timo : 1000 * timo;
6120 debug(F101,"netinc BSDSELECT","",timo);
6121
6122 for ( ; timeout >= 0; timeout -= (timo ? 100 : 0)) {
6123 int rc;
6124 debug(F111,"netinc","timeout",timeout);
6125 /* Don't move select() initialization out of the loop. */
6126 FD_ZERO(&rfds);
6127 FD_SET(ttyfd, &rfds);
6128 tv.tv_sec = tv.tv_usec = 0L;
6129 if (timo)
6130 tv.tv_usec = (long) 100000L;
6131 else
6132 tv.tv_sec = 30;
6133 #ifdef NT
6134 WSASafeToCancel = 1;
6135 #endif /* NT */
6136 rc = select(FD_SETSIZE,
6137 #ifdef __DECC
6138 #ifdef INTSELECT
6139 (int *)
6140 #else /* def INTSELECT */
6141 (fd_set *)
6142 #endif /* def INTSELECT [else] */
6143 #else /* def __DECC */
6144 (fd_set *)
6145 #endif /* def __DECC [else] */
6146 &rfds, NULL, NULL, &tv);
6147 if (rc < 0) {
6148 int s_errno = socket_errno;
6149 debug(F111,"netinc","select",rc);
6150 debug(F111,"netinc","socket_errno",s_errno);
6151 if (s_errno) {
6152 #ifdef OS2
6153 ReleaseTCPIPMutex();
6154 #endif /* OS2 */
6155 return(-1);
6156 }
6157 }
6158 debug(F111,"netinc","select",rc);
6159 #ifdef NT
6160 WSASafeToCancel = 0;
6161 #endif /* NT */
6162 if (!FD_ISSET(ttyfd, &rfds)) {
6163 #ifdef LEBUF
6164 if (le_inbuf() > 0) {
6165 timeout = -1;
6166 break;
6167 }
6168 #endif /* LEBUF */
6169 /* If waiting forever we have no way of knowing if the */
6170 /* socket closed so try writing a 0-length TCP packet */
6171 /* which should force an error if the socket is closed */
6172 if (!timo) {
6173 if ((rc = socket_write(ttyfd,"",0)) < 0) {
6174 int s_errno = socket_errno;
6175 debug(F101,"netinc socket_write error","",s_errno);
6176 #ifdef OS2
6177 if (os2socketerror(s_errno) < 0) {
6178 ReleaseTCPIPMutex();
6179 return(-2);
6180 }
6181 ReleaseTCPIPMutex();
6182 #endif /* OS2 */
6183 return(-1); /* Call it an i/o error */
6184 }
6185 }
6186 continue;
6187 }
6188 while (1) {
6189 if (ttbufr() < 0) { /* Keep trying to refill it. */
6190 timeout = -1;
6191 break; /* Till we get an error. */
6192 }
6193 if (ttibn > 0) { /* Or we get a character. */
6194 x = 0;
6195 timeout = -1;
6196 break;
6197 }
6198 }
6199 }
6200 #ifdef NT
6201 WSASafeToCancel = 0;
6202 #endif /* NT */
6203 #else /* !BSDSELECT */
6204 #ifdef IBMSELECT
6205 /*
6206 Was used by OS/2, currently not used, but might come in handy some day...
6207 ... and it came in handy! For our TCP/IP layer, it avoids all the fd_set
6208 and timeval stuff since this is the only place where it is used.
6209 */
6210 int socket = ttyfd;
6211 int timeout = timo < 0 ? -timo : 1000 * timo;
6212
6213 debug(F101,"netinc IBMSELECT","",timo);
6214 for ( ; timeout >= 0; timeout -= (timo ? 100 : 0)) {
6215 if (select(&socket, 1, 0, 0, 100L) == 1) {
6216 while (1) {
6217 if (ttbufr() < 0) { /* Keep trying to refill it. */
6218 timeout = -1;
6219 break; /* Till we get an error. */
6220 }
6221 if (ttibn > 0) { /* Or we get a character. */
6222 x = 0;
6223 timeout = -1;
6224 break;
6225 }
6226 }
6227 }
6228 #ifdef LEBUF
6229 else if (le_inbuf() > 0) {
6230 timeout = -1;
6231 break;
6232 }
6233 #endif /* LEBUF */
6234 }
6235 #else /* !IBMSELECT */
6236 #ifdef WINSOCK
6237 /* Actually, under WinSock we have a better mechanism than select() */
6238 /* for setting timeouts (SO_RCVTIMEO, SO_SNDTIMEO) */
6239 SOCKET socket = ttyfd;
6240 debug(F101,"netinc NTSELECT","",timo);
6241 if (setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, (char *)&timo,
6242 sizeof(timo)) == NO_ERROR)
6243 while (1) {
6244 if (ttbufr() < 0) /* Keep trying to refill it. */
6245 break; /* Till we get an error. */
6246 if (ttibn > 0) { /* Or we get a character. */
6247 x = 0;
6248 break;
6249 }
6250 }
6251 #else /* WINSOCK */
6252 /*
6253 If we can't use select(), then we use the regular alarm()/signal()
6254 timeout mechanism.
6255 */
6256 debug(F101,"netinc alarm","",timo);
6257 x = alrm_execute(ckjaddr(njbuf),timo,nettout,donetinc,failnetinc);
6258 ttimoff(); /* Timer off. */
6259 #endif /* WINSOCK */
6260 #endif /* IBMSELECT */
6261 #endif /* BSDSELECT */
6262 #endif /* NT_TCP_OVERLAPPED */
6263 }
6264 }
6265
6266 #ifdef LEBUF
6267 if (le_inbuf() > 0) { /* If data was inserted into the */
6268 if (le_getchar((CHAR *)&c) > 0) {/* Local Echo buffer while the */
6269 #ifdef OS2 /* was taking place do not mix */
6270 ReleaseTCPIPMutex(); /* the le data with the net data */
6271 #endif /* OS2 */
6272 return(c);
6273 }
6274 }
6275 #endif /* LEBUF */
6276 if (x < 0) { /* Return -1 if we failed. */
6277 debug(F100,"netinc timed out","",0);
6278 #ifdef OS2
6279 ReleaseTCPIPMutex();
6280 #endif /* OS2 */
6281 return(-1);
6282 } else { /* Otherwise */
6283 c = ttibuf[ttibp]; /* Return the first char in ttibuf[] */
6284 if (deblog) {
6285 #ifndef COMMENT
6286 debug(F101,"netinc returning","",c);
6287 #endif /* COMMENT */
6288 if (c == 0) {
6289 debug(F101,"netinc 0 ttibn","",ttibn);
6290 debug(F101,"netinc 0 ttibp","",ttibp);
6291 #ifdef BETADEBUG
6292 {
6293 #ifdef OS2
6294 extern int tt_type_mode;
6295 if ( !ISVTNT(tt_type_mode) )
6296 #endif /* OS2 */
6297 ckhexdump("netinc &ttbuf[ttibp]",&ttibuf[ttibp],ttibn);
6298 }
6299 #endif /* BETADEBUG */
6300 }
6301 }
6302 ttibp++;
6303 ttibn--;
6304 #ifdef OS2
6305 ReleaseTCPIPMutex();
6306 #endif /* OS2 */
6307 #ifdef CK_ENCRYPTION
6308 if (TELOPT_U(TELOPT_ENCRYPTION))
6309 ck_tn_decrypt(&c,1);
6310 #endif /* CK_ENCRYPTION */
6311 return(c);
6312 }
6313 #else /* Not using TCPIPLIB */
6314 return(-1);
6315 #endif /* TCPIPLIB */
6316 }
6317
6318 /* N E T T O L -- Output a string of bytes to the network */
6319 /*
6320 Call with s = pointer to string, n = length.
6321 Returns number of bytes actually written on success, or
6322 -1 on i/o error, -2 if called improperly.
6323 */
6324
6325 int
nettol(s,n)6326 nettol(s,n) CHAR *s; int n; {
6327 #ifdef TCPIPLIB
6328 int count = 0;
6329 int len = n;
6330 int try = 0;
6331
6332 if (ttyfd == -1) {
6333 debug(F100,"nettol socket is closed","",0);
6334 return -1;
6335 }
6336 debug(F101,"nettol TCPIPLIB ttnet","",ttnet);
6337 #ifdef COMMENT
6338 ckhexdump("nettol",s,n);
6339 #endif /* COMMENT */
6340
6341 #ifdef CK_KERBEROS
6342 #ifdef KRB4
6343 #ifdef RLOGCODE
6344 if (ttnproto == NP_EK4LOGIN) {
6345 return(krb4_des_write(ttyfd,s,n));
6346 }
6347 #endif /* RLOGCODE */
6348 #endif /* KRB4 */
6349 #ifdef KRB5
6350 #ifdef RLOGCODE
6351 if (ttnproto == NP_EK5LOGIN) {
6352 return(krb5_des_write(ttyfd,s,n,0));
6353 }
6354 #endif /* RLOGCODE */
6355 #ifdef KRB5_U2U
6356 if (ttnproto == NP_K5U2U) {
6357 return(krb5_u2u_write(ttyfd,s,n));
6358 }
6359 #endif /* KRB5_U2U */
6360 #endif /* KRB5 */
6361 #endif /* CK_KERBEROS */
6362
6363 #ifdef CK_ENCRYPTION
6364 if (TELOPT_ME(TELOPT_ENCRYPTION))
6365 ck_tn_encrypt(s,n);
6366 #endif /* CK_ENCRYPTION */
6367
6368 #ifdef CK_SSL
6369 if (ssl_active_flag || tls_active_flag) {
6370 int error, r;
6371 /* Write using SSL */
6372 ssl_retry:
6373 if (ssl_active_flag)
6374 r = SSL_write(ssl_con, s, len /* >1024?1024:len */);
6375 else
6376 r = SSL_write(tls_con, s, len /* >1024?1024:len */);
6377 switch (SSL_get_error(ssl_active_flag?ssl_con:tls_con,r)) {
6378 case SSL_ERROR_NONE:
6379 debug(F111,"nettol","SSL_write",r);
6380 if ( r == len )
6381 return(n);
6382 s += r;
6383 len -= r;
6384 goto ssl_retry;
6385 case SSL_ERROR_WANT_WRITE:
6386 debug(F100,"nettol SSL_ERROR_WANT_WRITE","",0);
6387 return(-1);
6388 case SSL_ERROR_WANT_READ:
6389 debug(F100,"nettol SSL_ERROR_WANT_READ","",0);
6390 return(-1);
6391 case SSL_ERROR_SYSCALL:
6392 if ( r == 0 ) { /* EOF */
6393 netclos();
6394 return(-2);
6395 } else {
6396 int rc = -1;
6397 #ifdef NT
6398 int gle = GetLastError();
6399 debug(F111,"nettol SSL_ERROR_SYSCALL",
6400 "GetLastError()",gle);
6401 rc = os2socketerror(gle);
6402 if (rc == -1)
6403 rc = -2;
6404 else if ( rc == -2 )
6405 rc = -1;
6406 #endif /* NT */
6407 return(rc);
6408 }
6409 case SSL_ERROR_WANT_X509_LOOKUP:
6410 debug(F100,"nettol SSL_ERROR_WANT_X509_LOOKUP","",0);
6411 netclos();
6412 return(-2);
6413 case SSL_ERROR_SSL:
6414 debug(F100,"nettol SSL_ERROR_SSL","",0);
6415 if (bio_err!=NULL) {
6416 int len;
6417 extern char ssl_err[];
6418 BIO_printf(bio_err,"nettol() SSL_ERROR_SSL\n");
6419 ERR_print_errors(bio_err);
6420 len = BIO_read(bio_err,ssl_err,SSL_ERR_BFSZ);
6421 ssl_err[len < SSL_ERR_BFSZ ? len : SSL_ERR_BFSZ] = '\0';
6422 debug(F110,"nettol SSL_ERROR_SSL",ssl_err,0);
6423 if (ssl_debug_flag)
6424 printf(ssl_err);
6425 } else if (ssl_debug_flag) {
6426 debug(F100,"nettol SSL_ERROR_SSL","",0);
6427 fflush(stderr);
6428 fprintf(stderr,"nettol() SSL_ERROR_SSL\n");
6429 ERR_print_errors_fp(stderr);
6430 }
6431 #ifdef COMMENT
6432 netclos();
6433 return(-2);
6434 #else
6435 return(-1);
6436 #endif
6437 case SSL_ERROR_ZERO_RETURN:
6438 debug(F100,"nettol SSL_ERROR_ZERO_RETURN","",0);
6439 netclos();
6440 return(-2);
6441 default:
6442 debug(F100,"nettol SSL_ERROR_?????","",0);
6443 netclos();
6444 return(-2);
6445 }
6446 }
6447 #endif /* CK_SSL */
6448
6449 nettol_retry:
6450 try++; /* Increase the try counter */
6451
6452 if (ttnet == NET_TCPB) {
6453 #ifdef BSDSELECT
6454 fd_set wfds;
6455 struct timeval tv;
6456
6457 debug(F101,"nettol BSDSELECT","",0);
6458 tv.tv_usec = 0L;
6459 tv.tv_sec=30;
6460 #ifdef NT
6461 WSASafeToCancel = 1;
6462 #endif /* NT */
6463 #ifdef STREAMING
6464 do_select:
6465 #endif /* STREAMING */
6466 FD_ZERO(&wfds);
6467 FD_SET(ttyfd, &wfds);
6468 if (select(FD_SETSIZE, NULL,
6469 #ifdef __DECC
6470 #ifndef __DECC_VER
6471 (int *)
6472 #endif /* __DECC_VER */
6473 #endif /* __DECC */
6474 &wfds, NULL, &tv) < 0) {
6475 int s_errno = socket_errno;
6476 debug(F101,"nettol select failed","",s_errno);
6477 #ifdef BETADEBUG
6478 printf("nettol select failed: %d\n", s_errno);
6479 #endif /* BETADEBUG */
6480 #ifdef NT
6481 WSASafeToCancel = 0;
6482 if (!win95selectbug)
6483 #endif /* NT */
6484 return(-1);
6485 }
6486 if (!FD_ISSET(ttyfd, &wfds)) {
6487 #ifdef STREAMING
6488 if (streaming)
6489 goto do_select;
6490 #endif /* STREAMING */
6491 debug(F111,"nettol","!FD_ISSET",ttyfd);
6492 #ifdef NT
6493 WSASafeToCancel = 0;
6494 if (!win95selectbug)
6495 #endif /* NT */
6496 return(-1);
6497 }
6498 #ifdef NT
6499 WSASafeToCancel = 0;
6500 #endif /* NT */
6501 #else /* BSDSELECT */
6502 #ifdef IBMSELECT
6503 {
6504 int tries = 0;
6505 debug(F101,"nettol IBMSELECT","",0);
6506 while (select(&ttyfd, 0, 1, 0, 1000) != 1) {
6507 int count;
6508 if (tries++ >= 60) {
6509 /* if after 60 seconds we can't get permission to write */
6510 debug(F101,"nettol select failed","",socket_errno);
6511 return(-1);
6512 }
6513 if ((count = nettchk()) < 0) {
6514 debug(F111,"nettol","nettchk()",count);
6515 return(count);
6516 }
6517 }
6518 }
6519 #endif /* IBMSELECT */
6520 #endif /* BSDSELECT */
6521 if ((count = socket_write(ttyfd,s,n)) < 0) {
6522 int s_errno = socket_errno; /* maybe a function */
6523 debug(F101,"nettol socket_write error","",s_errno);
6524 #ifdef OS2
6525 if (os2socketerror(s_errno) < 0)
6526 return(-2);
6527 #endif /* OS2 */
6528 return(-1); /* Call it an i/o error */
6529 }
6530 if (count < n) {
6531 debug(F111,"nettol socket_write",s,count);
6532 if (try > 25) {
6533 /* don't try more than 25 times */
6534 debug(F100,"nettol tried more than 25 times","",0);
6535 return(-1);
6536 }
6537 if (count > 0) {
6538 s += count;
6539 n -= count;
6540 }
6541 debug(F111,"nettol retry",s,n);
6542 goto nettol_retry;
6543 } else {
6544 debug(F111,"nettol socket_write",s,count);
6545 return(len); /* success - return total length */
6546 }
6547 } else
6548 return(-2);
6549 #else
6550 debug(F100,"nettol TCPIPLIB not defined","",0);
6551 return(-2);
6552 #endif /* TCPIPLIB */
6553 }
6554
6555 /* N E T T O C -- Output character to network */
6556 /*
6557 Call with character to be transmitted.
6558 Returns 0 if transmission was successful, or
6559 -1 upon i/o error, or -2 if called improperly.
6560 */
6561 int
6562 #ifdef CK_ANSIC
nettoc(CHAR c)6563 nettoc(CHAR c)
6564 #else
6565 nettoc(c) CHAR c;
6566 #endif /* CK_ANSIC */
6567 /* nettoc */ {
6568 #ifdef UNIX
6569 return(ttoc(c));
6570 #else
6571 #ifdef TCPIPLIB
6572 unsigned char cc;
6573 if (ttyfd == -1) {
6574 debug(F100,"nettoc socket is closed","",0);
6575 return -1;
6576 }
6577 cc = c;
6578 debug(F101,"nettoc cc","",cc);
6579
6580 #ifdef CK_KERBEROS
6581 #ifdef KRB4
6582 #ifdef RLOGCODE
6583 if (ttnproto == NP_EK4LOGIN) {
6584 return(krb4_des_write(ttyfd,&cc,1)==1?0:-1);
6585 }
6586 #endif /* RLOGCODE */
6587 #endif /* KRB4 */
6588 #ifdef KRB5
6589 #ifdef RLOGCODE
6590 if (ttnproto == NP_EK5LOGIN) {
6591 return(krb5_des_write(ttyfd,&cc,1,0)==1?0:-1);
6592 }
6593 #endif /* RLOGCODE */
6594 #ifdef KRB5_U2U
6595 if (ttnproto == NP_K5U2U) {
6596 return(krb5_u2u_write(ttyfd,&cc,1)==1?0:-1);
6597 }
6598 #endif /* KRB5_U2U */
6599 #endif /* KRB5 */
6600 #endif /* CK_KERBEROS */
6601
6602 #ifdef CK_ENCRYPTION
6603 if ( TELOPT_ME(TELOPT_ENCRYPTION) )
6604 ck_tn_encrypt(&cc,1);
6605 #endif /* CK_ENCRYPTION */
6606 #ifdef CK_SSL
6607 if (ssl_active_flag || tls_active_flag) {
6608 int len, error;
6609 /* Write using SSL */
6610 ssl_retry:
6611 if (ssl_active_flag)
6612 len = SSL_write(ssl_con, &cc, 1);
6613 else
6614 len = SSL_write(tls_con, &cc, 1);
6615 switch (SSL_get_error(ssl_active_flag?ssl_con:tls_con,len)) {
6616 case SSL_ERROR_NONE:
6617 debug(F111,"nettoc","SSL_write",len);
6618 return(len == 1 ? 0 : -1);
6619 case SSL_ERROR_WANT_WRITE:
6620 case SSL_ERROR_WANT_READ:
6621 return(-1);
6622 case SSL_ERROR_SYSCALL:
6623 if ( len == 0 ) { /* EOF */
6624 netclos();
6625 return(-2);
6626 } else {
6627 int rc = -1;
6628 #ifdef NT
6629 int gle = GetLastError();
6630 debug(F111,"nettoc SSL_ERROR_SYSCALL",
6631 "GetLastError()",gle);
6632 rc = os2socketerror(gle);
6633 if (rc == -1)
6634 rc = -2;
6635 else if ( rc == -2 )
6636 rc = -1;
6637 #endif /* NT */
6638 return(rc);
6639 }
6640 case SSL_ERROR_SSL:
6641 if (bio_err!=NULL) {
6642 int len;
6643 extern char ssl_err[];
6644 BIO_printf(bio_err,"nettoc() SSL_ERROR_SSL\n");
6645 ERR_print_errors(bio_err);
6646 len = BIO_read(bio_err,ssl_err,SSL_ERR_BFSZ);
6647 ssl_err[len < SSL_ERR_BFSZ ? len : SSL_ERR_BFSZ] = '\0';
6648 debug(F110,"nettoc SSL_ERROR_SSL",ssl_err,0);
6649 if (ssl_debug_flag)
6650 printf(ssl_err);
6651 } else if (ssl_debug_flag) {
6652 debug(F100,"nettoc SSL_ERROR_SSL","",0);
6653 fflush(stderr);
6654 fprintf(stderr,"nettoc() SSL_ERROR_SSL\n");
6655 ERR_print_errors_fp(stderr);
6656 }
6657 return(-1);
6658 break;
6659 case SSL_ERROR_WANT_X509_LOOKUP:
6660 case SSL_ERROR_ZERO_RETURN:
6661 default:
6662 netclos();
6663 return(-2);
6664 }
6665 }
6666 #endif /* CK_SSL */
6667 if (ttnet == NET_TCPB) {
6668 #ifdef BSDSELECT
6669 fd_set wfds;
6670 struct timeval tv;
6671
6672 debug(F101,"nettoc BSDSELECT","",0);
6673 tv.tv_usec = 0L;
6674 tv.tv_sec = 30;
6675
6676 #ifdef STREAMING
6677 do_select:
6678 #endif /* STREAMING */
6679
6680 FD_ZERO(&wfds);
6681 FD_SET(ttyfd, &wfds);
6682 if (select(FD_SETSIZE, NULL,
6683 #ifdef __DECC
6684 #ifndef __DECC_VER
6685 (int *)
6686 #endif /* __DECC_VER */
6687 #endif /* __DECC */
6688 &wfds, NULL, &tv) < 0) {
6689 int s_errno = socket_errno;
6690 debug(F101,"nettoc select failed","",s_errno);
6691 #ifdef BETADEBUG
6692 printf("nettoc select failed: %d\n", s_errno);
6693 #endif /* BETADEBUG */
6694 #ifdef NT
6695 WSASafeToCancel = 0;
6696 if (!win95selectbug)
6697 #endif /* NT */
6698 return(-1);
6699 }
6700 if (!FD_ISSET(ttyfd, &wfds)) {
6701 #ifdef STREAMING
6702 if (streaming)
6703 goto do_select;
6704 #endif /* STREAMING */
6705 debug(F111,"nettoc","!FD_ISSET",ttyfd);
6706 #ifdef NT
6707 WSASafeToCancel = 0;
6708 if (!win95selectbug)
6709 #endif /* NT */
6710 return(-1);
6711 }
6712 #ifdef NT
6713 WSASafeToCancel = 0;
6714 #endif /* NT */
6715 #else /* BSDSELECT */
6716 #ifdef IBMSELECT
6717 {
6718 int tries = 0;
6719 while (select(&ttyfd, 0, 1, 0, 1000) != 1) {
6720 int count;
6721 if (tries++ >= 60) {
6722 /* if after 60 seconds we can't get permission to write */
6723 debug(F101,"nettoc select failed","",socket_errno);
6724 return(-1);
6725 }
6726 if ((count = nettchk()) < 0) {
6727 debug(F111,"nettoc","nettchk()",count);
6728 return(count);
6729 }
6730 }
6731 }
6732 #endif /* IBMSELECT */
6733 #endif /* BSDSELECT */
6734 if (socket_write(ttyfd,&cc,1) < 1) {
6735 int s_errno = socket_errno; /* maybe a function */
6736 debug(F101,"nettoc socket_write error","",s_errno);
6737 #ifdef OS2
6738 if (os2socketerror(s_errno) < 0)
6739 return(-2);
6740 #endif /* OS2 */
6741 return(-1);
6742 }
6743 debug(F101,"nettoc socket_write","", cc);
6744 return(0);
6745 } else return(-2);
6746 #else
6747 return(-2);
6748 #endif /* TCPIPLIB */
6749 #endif /* UNIX */
6750 }
6751
6752 /* N E T F L U I -- Flush network input buffer */
6753
6754 #ifdef TNCODE
6755 static int
6756 #ifdef CK_ANSIC
netgetc(int timo)6757 netgetc(int timo) /* Input function to point to... */
6758 #else /* CK_ANSIC */
6759 netgetc(timo) int timo;
6760 #endif /* CK_ANSIC */
6761 { /* ...in the tn_doop() call */
6762 #ifdef TCPIPLIB
6763 return netinc(timo);
6764 #else /* TCPIPLIB */
6765 return ttinc(timo);
6766 #endif /* TCPIPLIB */
6767 }
6768 #endif /* TNCODE */
6769
6770 int
netflui()6771 netflui() {
6772 int n;
6773 int ch;
6774 #ifdef NETLEBUF
6775 ttpush = -1; /* Clear the peek-ahead char */
6776 while (le_data && (le_inbuf() > 0)) {
6777 CHAR ch = '\0';
6778 if (le_getchar(&ch) > 0) {
6779 debug(F101,"ttflui le_inbuf ch","",ch);
6780 }
6781 }
6782 #endif /* NETLEBUF */
6783
6784 #ifdef TCPIPLIB
6785 #ifdef OS2
6786 RequestTCPIPMutex(SEM_INDEFINITE_WAIT);
6787 #endif /* OS2 */
6788 #ifdef TNCODE
6789 if (ttnproto == NP_TELNET) {
6790 /* Netflui must process Telnet negotiations or get out of sync */
6791 if ((n = nettchk()) <= 0)
6792 goto exit_flui;
6793 while (n-- > 0) {
6794 ch = netinc(1);
6795 if (ch == IAC) {
6796 extern int duplex; /* this really shouldn't be here but ... */
6797 int tx = tn_doop((CHAR)(ch & 0xff),duplex,netgetc);
6798 if (tx == 1) duplex = 1;
6799 else if (tx == 2) duplex = 0;
6800 n = nettchk();
6801 }
6802 }
6803 } else
6804 #endif /* TNCODE */
6805 {
6806 ttibuf[ttibp+ttibn] = '\0';
6807 debug(F111,"netflui 1",ttibuf,ttibn);
6808 #ifdef CK_ENCRYPTION
6809 if (TELOPT_U(TELOPT_ENCRYPTION)) {
6810 ck_tn_decrypt(&ttibuf[ttibp],ttibn);
6811 }
6812 #endif /* CK_ENCRYPTION */
6813 ttibn = ttibp = 0; /* Flush internal buffer *FIRST* */
6814 if (ttyfd < 1)
6815 goto exit_flui;
6816 if ((n = nettchk()) > 0) { /* Now see what's waiting on the net */
6817 if (n > TTIBUFL) n = TTIBUFL; /* and sponge it up */
6818 debug(F101,"netflui 2","",n); /* ... */
6819 n = socket_read(ttyfd,ttibuf,n); /* into our buffer */
6820 if (n >= 0) ttibuf[n] = '\0';
6821 debug(F111,"netflui 3",ttibuf,n);
6822 #ifdef CK_ENCRYPTION
6823 if (TELOPT_U(TELOPT_ENCRYPTION)) {
6824 ck_tn_decrypt(&ttibuf[ttibp],n);
6825 }
6826 #endif /* CK_ENCRYPTION */
6827 ttibuf[0] = '\0';
6828 }
6829 }
6830 #else /* !TCPIPLIB */
6831 if (ttyfd < 1)
6832 goto exit_flui;
6833 #ifdef TNCODE
6834 if (ttnproto == NP_TELNET) {
6835 if ((n = ttchk()) <= 0)
6836 goto exit_flui;
6837 while (n-- >= 0) {
6838 /* Netflui must process Telnet negotiations or get out of sync */
6839 ch = ttinc(1);
6840 if (ch == IAC) {
6841 extern int duplex; /* this really shouldn't be here but ... */
6842 int tx = tn_doop((CHAR)(ch & 0xff),duplex,netgetc);
6843 if (tx == 1) duplex = 1;
6844 else if (tx == 2) duplex = 0;
6845 n = ttchk();
6846 }
6847 };
6848 } else
6849 #endif /* TNCODE */
6850 if ((n = ttchk()) > 0) {
6851 debug(F101,"netflui non-TCPIPLIB","",n);
6852 while ((n--) && ttinc(1) > -1) /* Don't worry, ttinc() is buffered */
6853 ; /* and it handles the decryption... */
6854 }
6855 #endif /* TCPIPLIB */
6856 exit_flui:
6857 #ifdef OS2
6858 ReleaseTCPIPMutex();
6859 #endif /* OS2 */
6860 return(0);
6861 }
6862
6863 #ifdef CK_KERBEROS
6864 /* The following two functions are required for encrypted rlogin */
6865 /* They are called with nettoc() or nettol() are transmitting */
6866 /* encrypted data. They call a function to encrypt the data */
6867 /* and that function needs to be able to write to/read from the */
6868 /* network in an unimpeded manner. Hence, these two simple fns. */
6869 int
net_write(fd,buf,len)6870 net_write(fd, buf, len)
6871 int fd;
6872 register const char *buf;
6873 int len;
6874 {
6875 int cc;
6876 register int wrlen = len;
6877 do {
6878 #ifdef TCPIPLIB
6879 cc = socket_write(fd, buf, wrlen);
6880 #else
6881 cc = write(fd,buf,wrlen);
6882 #endif /* TCPIPLIB */
6883 if (cc < 0) {
6884 int s_errno = socket_errno;
6885 debug(F101,"net_write error","",s_errno);
6886 #ifdef OS2
6887 if (os2socketerror(s_errno) < 0)
6888 return(-1);
6889 else
6890 continue;
6891 #else /* OS2 */
6892 if (errno == EINTR)
6893 continue;
6894 return(-1);
6895 #endif /* OS2 */
6896 }
6897 else {
6898 buf += cc;
6899 wrlen -= cc;
6900 }
6901 } while (wrlen > 0);
6902 return(len);
6903 }
6904 int
net_read(fd,buf,len)6905 net_read(fd, buf, len)
6906 int fd;
6907 register char *buf;
6908 register int len;
6909 {
6910 int cc, len2 = 0;
6911
6912 do {
6913 #ifdef TCPIPLIB
6914 cc = socket_read(fd, buf, len);
6915 #else
6916 cc = read(fd,buf,len);
6917 #endif
6918 if (cc < 0) {
6919 int s_errno = socket_errno;
6920 debug(F101,"net_read error","",s_errno);
6921 #ifdef OS2
6922 if (os2socketerror(s_errno) < 0)
6923 return(-1);
6924 #endif /* OS2 */
6925 return(cc); /* errno is already set */
6926 }
6927 else if (cc == 0) {
6928 netclos();
6929 return(len2);
6930 } else {
6931 buf += cc;
6932 len2 += cc;
6933 len -= cc;
6934 }
6935 } while (len > 0);
6936 return(len2);
6937 }
6938 #endif /* CK_KERBEROS */
6939 #endif /* NONET */
6940
6941 /* getlocalipaddr() attempts to resolve an IP Address for the local machine.
6942 * If the host is multi-homed it returns only one address.
6943 *
6944 * Two techniques are used.
6945 * (1) get the local host name and perform a DNS lookup, then take
6946 * the first entry;
6947 * (2) open a UDP socket, use it to connect to a fictitious host (it's OK,
6948 * no data is sent), then retrieve the local address from the socket.
6949 * Note: the second technique won't work on Microsoft systems. See
6950 * Article ID: Q129065 PRB: Getsockname() Returns IP Address 0.0.0.0 for UDP
6951 */
6952
6953 /* Technique number one cannot work reliably if the machine is a laptop
6954 * and the hostname is associated with a physical adapter which is not
6955 * installed and a PPP connection is being used instead. This is because
6956 * the hostname DNS lookup will succeed for the physical adapter even though
6957 * it would be impossible to use it. In NT4 SP4, the gethostbyname()
6958 * when given the result of gethostname() returns not the real DNS entries
6959 * for that name+domain. Instead it returns all of the static and dynamic
6960 * IP addresses assigned to any physical or virtual adapter defined in the
6961 * system regardless of whether or not it is installed. The order of the
6962 * addresses is fixed according to the binding order in the NT registry.
6963 */
6964
6965 /*
6966 * It appears that calling gethostbyname(NULL) is more reliable than
6967 * calling gethostbyname(gethostname()) on Windows. So on Windows we will
6968 * only call gethostbyname(NULL).
6969 */
6970
6971 int
getlocalipaddr()6972 getlocalipaddr() {
6973 #ifndef datageneral
6974 struct sockaddr_in l_sa;
6975 struct sockaddr_in r_sa;
6976 GSOCKNAME_T slen = sizeof(struct sockaddr_in);
6977 int sock;
6978 int rc;
6979 struct in_addr laddr;
6980
6981 /* if still not resolved, then try second strategy */
6982 /* This second strategy does not work on Windows */
6983
6984 debug(F100,"getlocalipaddr","",0);
6985 memset(&l_sa,0,slen);
6986 memset(&r_sa,0,slen);
6987
6988 /* get a UDP socket */
6989 sock = socket(AF_INET, SOCK_DGRAM, 0);
6990 if (sock != -1) {
6991 /* connect to arbirary port and address (NOT loopback) */
6992 r_sa.sin_family = AF_INET;
6993 r_sa.sin_port = htons(IPPORT_ECHO);
6994
6995 /* The following is an "illegal conversion" in AOS/VS */
6996 /* (and who knows where else) */
6997
6998 #ifdef INADDRX
6999 inaddrx = inet_addr("128.127.50.1");
7000 r_sa.sin_addr.s_addr = *(unsigned long *)&inaddrx;
7001 #else
7002 r_sa.sin_addr.s_addr = inet_addr("128.127.50.1");
7003 #endif /* INADDRX */
7004 rc = connect(sock, (struct sockaddr *) &r_sa, sizeof(struct sockaddr));
7005 if (!rc) { /* get local address */
7006 getsockname(sock,(struct sockaddr *)&l_sa,&slen);
7007 #ifdef TCPIPLIB
7008 socket_close(sock); /* We're done with the socket */
7009 #else
7010 close(sock);
7011 #endif /* TCPIPLIB */
7012 if (l_sa.sin_addr.s_addr != INADDR_ANY) {
7013 myxipaddr = ntohl(l_sa.sin_addr.s_addr);
7014 ckstrncpy(myipaddr,(char *)inet_ntoa(l_sa.sin_addr),20);
7015 debug(F110,"getlocalipaddr setting buf to",myipaddr,0);
7016 return(0);
7017 }
7018 }
7019 }
7020 return getlocalipaddrs(myipaddr,sizeof(myipaddr),0);
7021 #else /* datageneral */
7022 return(-1);
7023 #endif /* datageneral */
7024 }
7025
7026 int
getlocalipaddrs(buf,bufsz,index)7027 getlocalipaddrs(buf,bufsz,index)
7028 char * buf;
7029 int bufsz;
7030 int index;
7031 /* getlocalipaddrs */ {
7032 #ifndef datageneral
7033 char localhost[256];
7034 struct hostent * host=NULL;
7035 struct sockaddr_in l_sa;
7036 struct sockaddr_in r_sa;
7037 GSOCKNAME_T slen = sizeof(struct sockaddr_in);
7038 int rc;
7039 #ifdef COMMENT
7040 int sock;
7041 char messageBuf[60];
7042 struct in_addr laddr;
7043 #endif /* COMMENT */
7044
7045 debug(F100,"getlocalipaddrs","",0);
7046 memset(&l_sa,0,slen);
7047 memset(&r_sa,0,slen);
7048
7049 /* init local address (to zero) */
7050 l_sa.sin_addr.s_addr = INADDR_ANY;
7051
7052 #ifdef CKGHNLHOST
7053 rc = gethostname(localhost, 256);
7054 debug(F110,"getlocalipaddrs localhost",localhost,0);
7055 #else
7056 /* This doesn't work on some platforms, e.g. Solaris */
7057 rc = 0;
7058 localhost[0] = '\0';
7059 #ifdef NT
7060 if ( winsock_version < 20 ) {
7061 rc = gethostname(localhost, 256);
7062 debug(F110,"getlocalipaddrs localhost",localhost,0);
7063 }
7064 #endif /* NT */
7065 #endif /* CKGHNLHOST */
7066 if (!rc) {
7067 /* resolve host name for local address */
7068 debug(F110,"getlocalipaddrs","calling gethostbyname()",0);
7069 host = gethostbyname(localhost);
7070 /* debug(F111,"getlocalipaddrs","gethostbyname() returned",host); */
7071 if (host) {
7072 #ifdef HADDRLIST
7073 host = ck_copyhostent(host);
7074 if ( index < 0 || index > 63 || !host->h_addr_list[index] ) {
7075 buf[0] = '\0';
7076 return(-1);
7077 }
7078 l_sa.sin_addr.s_addr =
7079 *((unsigned long *) (host->h_addr_list[index]));
7080 ckstrncpy(buf,(char *)inet_ntoa(l_sa.sin_addr),20);
7081 debug(F110,"getlocalipaddrs setting buf to",buf,0);
7082
7083 #ifdef COMMENT
7084 /* This is for reporting multiple IP Address */
7085 while (host->h_addr_list && host->h_addr_list[0]) {
7086 l_sa.sin_addr.s_addr =
7087 *((unsigned long *) (host->h_addr_list[0]));
7088 ckstrncpy(messageBuf,
7089 (char *)inet_ntoa(l_sa.sin_addr),60);
7090 if (tcp_address) {
7091 if (!strcmp(messageBuf,tcp_address))
7092 ckstrncpy(myipaddr,tcp_address,20);
7093 }
7094 debug(F110,"getlocalipaddrs ip address list", messageBuf, 0);
7095 host->h_addr_list++;
7096 }
7097 #endif /* COMMENT */
7098 #else /* HADDRLIST */
7099 if (index != 0) {
7100 buf[0] = '\0';
7101 return(-1);
7102 }
7103 l_sa.sin_addr.s_addr = *((unsigned long *) (host->h_addr));
7104 ckstrncpy(buf,(char *)inet_ntoa(l_sa.sin_addr),bufsz);
7105 debug(F110,"getlocalipaddrs setting buf to",buf,0);
7106 #endif /* HADDRLIST */
7107 return(0);
7108 } else debug(F110,
7109 "getlocalipaddrs: gethostbyname() failed",
7110 localhost,
7111 0
7112 );
7113 }
7114 #endif /* datageneral */
7115 return(-1);
7116 }
7117
7118 #ifdef RLOGCODE /* TCP/IP RLOGIN protocol support code */
7119 int
rlog_naws()7120 rlog_naws() {
7121 struct rlog_naws {
7122 unsigned char id[4];
7123 unsigned short rows, cols, ypix, xpix;
7124 } nawsbuf;
7125
7126 if (ttnet != NET_TCPB)
7127 return 0;
7128 if (ttnproto != NP_RLOGIN
7129 #ifdef CK_KERBEROS
7130 && ttnproto != NP_K4LOGIN
7131 && ttnproto != NP_EK4LOGIN
7132 && ttnproto != NP_K5LOGIN
7133 && ttnproto != NP_EK5LOGIN
7134 #endif /* CK_KERBEROS */
7135 )
7136 return 0;
7137 if (!TELOPT_ME(TELOPT_NAWS))
7138 return 0;
7139
7140 debug(F100,"rlogin Window Size sent","",0);
7141
7142 nawsbuf.id[0] = nawsbuf.id[1] = 0377;
7143 nawsbuf.id[2] = nawsbuf.id[3] = 's';
7144 #ifdef OS2
7145 nawsbuf.rows = htons((unsigned short) (VscrnGetHeight(VTERM)
7146 -(tt_status[VTERM]?1:0)));
7147 nawsbuf.cols = htons((unsigned short) VscrnGetWidth(VTERM));
7148 #else /* OS2 */
7149 nawsbuf.rows = htons((unsigned short) tt_rows);
7150 nawsbuf.cols = htons((unsigned short) tt_cols);
7151 #endif /* OS2 */
7152 nawsbuf.ypix = htons(0); /* y pixels */
7153
7154 nawsbuf.xpix = htons(0); /* x pixels */
7155 if (ttol((CHAR *)(&nawsbuf), sizeof(nawsbuf)) < 0)
7156 return(-1);
7157 return(0);
7158 }
7159
7160 #ifdef OS2ORUNIX
7161 #define RLOGOUTBUF
7162 #endif /* OS2 */
7163 static int
7164 #ifdef CK_ANSIC
rlog_ini(CHAR * hostname,int port,struct sockaddr_in * l_addr,struct sockaddr_in * r_addr)7165 rlog_ini(CHAR * hostname, int port,
7166 struct sockaddr_in * l_addr, struct sockaddr_in * r_addr)
7167 #else /* CK_ANSIC */
7168 rlog_ini(hostname, port, l_addr, r_addr)
7169 CHAR * hostname;
7170 int port;
7171 struct sockaddr_in * l_addr;
7172 struct sockaddr_in * r_addr;
7173 #endif /* CK_ANSIC */
7174 /* rlog_ini */ {
7175
7176 #ifdef RLOGOUTBUF
7177 char outbuf[512];
7178 int outbytes=0;
7179 #endif /* RLOGOUTBUF */
7180 int flag = 0;
7181 #define TERMLEN 16
7182 #define CONSPDLEN 16
7183 CHAR localuser[UIDBUFLEN+1];
7184 CHAR remoteuser[UIDBUFLEN+1];
7185 int userlen = 0;
7186 CHAR term_speed[TERMLEN+CONSPDLEN+1];
7187 #ifdef CONGSPD
7188 long conspd = -1L;
7189 #endif /* CONGSPD */
7190 #ifdef OS2
7191 extern int tt_type, max_tt;
7192 extern struct tt_info_rec tt_info[];
7193 #endif /* OS2 */
7194 int i, n;
7195
7196 int rc = 0;
7197 tn_reset(); /* This call will reset all of the Telnet */
7198 /* options and then quit. We need to do */
7199 /* this since we use the Telnet options */
7200 /* to hold various state information */
7201 duplex = 0; /* Rlogin is always remote echo */
7202 rlog_inband = 0;
7203
7204 #ifdef CK_TTGWSIZ
7205 /*
7206 But compute the values anyway before the first read since the out-
7207 of-band NAWS request would arrive before the first data byte (NULL).
7208 */
7209 #ifdef OS2
7210 /* Console terminal screen rows and columns */
7211 debug(F101,"rlog_ini tt_rows 1","",VscrnGetHeight(VTERM)
7212 -(tt_status[VTERM]?1:0));
7213 debug(F101,"rlog_ini tt_cols 1","",VscrnGetWidth(VTERM));
7214 /* Not known yet */
7215 if (VscrnGetWidth(VTERM) < 0 ||
7216 VscrnGetHeight(VTERM)-(tt_status[VTERM]?1:0) < 0) {
7217 ttgwsiz(); /* Try to get screen dimensions */
7218 }
7219 debug(F101,
7220 "rlog_ini tt_rows 2",
7221 "",
7222 VscrnGetHeight(VTERM)-(tt_status[VTERM]?1:0)
7223 );
7224 debug(F101,"rlog_ini tt_cols 2","",VscrnGetWidth(VTERM));
7225 #else /* OS2 */
7226 debug(F101,"rlog_ini tt_rows 1","",tt_rows);
7227 debug(F101,"rlog_ini tt_cols 1","",tt_cols);
7228 if (tt_rows < 0 || tt_cols < 0) { /* Not known yet */
7229 ttgwsiz(); /* Try to find out */
7230 }
7231 debug(F101,"rlog_ini tt_rows 2","",tt_rows);
7232 debug(F101,"rlog_ini tt_cols 2","",tt_cols);
7233 #endif /* OS2 */
7234 #endif /* CK_TTGWSIZ */
7235
7236 ttflui(); /* Start by flushing the buffers */
7237
7238 rlog_mode = RL_COOKED;
7239
7240 /* Determine the user's local username ... */
7241
7242 localuser[0] = '\0';
7243 #ifdef NT
7244 {
7245 char localuid[UIDBUFLEN+1];
7246 ckstrncpy((char *)localuser,(char *)GetLocalUser(),UIDBUFLEN);
7247 }
7248
7249 if ( !localuser[0] )
7250 #endif /* NT */
7251 {
7252 char * user = getenv("USER");
7253 if (!user)
7254 user = "";
7255 userlen = strlen(user);
7256 debug(F111,"rlogin getenv(USER)",user,userlen);
7257 ckstrncpy((char *)localuser,user,UIDBUFLEN);
7258 debug(F110,"rlog_ini localuser 1",localuser,0);
7259 }
7260 if ( !localuser[0] )
7261 strcpy((char *)localuser,"unknown");
7262 else if (ck_lcname) {
7263 cklower((char *)localuser);
7264 debug(F110,"rlog_ini localuser 2",localuser,0);
7265 }
7266
7267 /* And the username to login with */
7268 if (uidbuf[0]) {
7269 ckstrncpy((char *)remoteuser,uidbuf,UIDBUFLEN);
7270 debug(F110,"rlog_ini remoteuser 1",remoteuser,0);
7271 } else if (localuser[0]) {
7272 ckstrncpy((char *)remoteuser,(char *)localuser,UIDBUFLEN);
7273 debug(F110,"rlog_ini remoteuser 2",remoteuser,0);
7274 } else {
7275 remoteuser[0] = '\0';
7276 debug(F110,"rlog_ini remoteuser 3",remoteuser,0);
7277 }
7278 if (ck_lcname)
7279 cklower((char *)remoteuser);
7280 debug(F110,"rlog_ini remoteuser 4",remoteuser,0);
7281
7282 /* The command to issue is the terminal type and speed */
7283 term_speed[0] = '\0';
7284 if (tn_term) { /* SET TELNET TERMINAL-TYPE value */
7285 if (*tn_term) { /* (if any) takes precedence. */
7286 ckstrncpy((char *)term_speed, tn_term, TERMLEN);
7287 flag = 1;
7288 }
7289 } else { /* Otherwise the local terminal type */
7290 #ifdef OS2
7291 /* In terminal-emulating versions, it's the SET TERM TYPE value */
7292 ckstrncpy(term_speed, (tt_type >= 0 && tt_type <= max_tt) ?
7293 tt_info[tt_type].x_name : "network", TERMLEN);
7294 #else
7295 /* In the others, we just look at the TERM environment variable */
7296 {
7297 char *p = getenv("TERM");
7298 if (p)
7299 ckstrncpy((char *)term_speed,p,TERMLEN);
7300 else
7301 term_speed[0] = '\0';
7302 #ifdef VMS
7303 for (p = (char *) term_speed; *p; p++) {
7304 if (*p == '-' && (!strcmp(p,"-80") || !strcmp(p,"-132")))
7305 break;
7306 else if (isupper(*p))
7307 *p = tolower(*p);
7308 }
7309 *p = '\0';
7310 #endif /* VMS */
7311 }
7312 #endif /* OS2 */
7313 }
7314 n = strlen((char *)term_speed);
7315 if (n > 0) { /* We have a terminal type */
7316 if (!flag) { /* If not user-specified */
7317 for (i = 0; i < n; i++) /* then lowercase it. */
7318 if (isupper(term_speed[i]))
7319 term_speed[i] = tolower(term_speed[i]);
7320 }
7321 debug(F110,"rlog_ini term_speed 1",term_speed,0);
7322
7323 #ifdef CONGSPD
7324 /* conspd() is not yet defined in all ck*tio.c modules */
7325 conspd = congspd();
7326 if (conspd > 0L) {
7327 ckstrncat((char *)term_speed,"/",sizeof(term_speed));
7328 ckstrncat((char *)term_speed,ckltoa(conspd),sizeof(term_speed));
7329 } else
7330 #endif /* CONGSPD */
7331 ckstrncat((char *)term_speed,"/19200",sizeof(term_speed));
7332 debug(F110,"rlog_ini term_speed 2",term_speed,0);
7333 } else {
7334 term_speed[0] = '\0';
7335 debug(F110,"rlog_ini term_speed 3",term_speed,0);
7336 }
7337
7338 #ifdef CK_KERBEROS
7339 if (ttnproto == NP_K4LOGIN || ttnproto == NP_EK4LOGIN ||
7340 ttnproto == NP_K5LOGIN || ttnproto == NP_EK5LOGIN) {
7341 int kver, encrypt, rc;
7342 switch (ttnproto) {
7343 case NP_K4LOGIN:
7344 kver = 4;
7345 encrypt = 0;
7346 break;
7347 case NP_EK4LOGIN:
7348 kver = 4;
7349 encrypt = 1;
7350 break;
7351 case NP_K5LOGIN:
7352 kver = 5;
7353 encrypt = 0;
7354 break;
7355 case NP_EK5LOGIN:
7356 kver = 5;
7357 encrypt = 1;
7358 break;
7359 default:
7360 kver = 0;
7361 encrypt = 0;
7362 }
7363 rc = ck_krb_rlogin(hostname, port,
7364 localuser, remoteuser, term_speed,
7365 l_addr, r_addr, kver, encrypt);
7366 if (!rc) { /* success */
7367 TELOPT_ME(TELOPT_NAWS) = 1;
7368 rc = rlog_naws();
7369 }
7370 return(rc);
7371 } else
7372 #endif /* CK_KERBEROS */
7373 if (ttnproto == NP_RLOGIN) {
7374 #ifdef RLOGOUTBUF
7375 /*
7376 * The rcmds start the connection with a series of init data:
7377 *
7378 * a port number upon which client is listening for stderr data
7379 * the user's name on the client machine
7380 * the user's name on the server machine
7381 * the terminal_type/speed or command to execute
7382 */
7383 outbuf[outbytes++] = 0;
7384 strcpy((char *)outbuf+outbytes,(char *)localuser);
7385 outbytes += strlen((char *)localuser) + 1;
7386 strcpy((char *)outbuf+outbytes,(char *)remoteuser);
7387 outbytes += strlen((char *)remoteuser) + 1;
7388 strcpy((char *)outbuf+outbytes,(char *)term_speed);
7389 outbytes += strlen((char *)term_speed) + 1;
7390 rc = ttol((CHAR *)outbuf,outbytes);
7391 #else /* RLOGOUTBUF */
7392 ttoc(0); /* Send an initial NUL as wake-up */
7393 /* Send each variable with the trailing NUL */
7394 rc = ttol(localuser,strlen((char *)localuser)+1);
7395 if (rc > 0)
7396 rc = ttol(remoteuser,strlen((char *)remoteuser)+1);
7397 if (rc > 0)
7398 rc = ttol(term_speed,strlen((char *)term_speed)+1);
7399 #endif /* RLOGOUTBUF */
7400
7401 /* Now we are supposed to get back a single NUL as confirmation */
7402 errno = 0;
7403 rc = ttinc(60);
7404 debug(F101,"rlogin first ttinc","",rc);
7405 if (rc > 0) {
7406 debug(F101,"rlogin ttinc 1","",rc);
7407 printf(
7408 "Rlogin protocol error - 0x%x received instead of 0x00\n", rc);
7409 return(-1);
7410 } else if (rc < 0) {
7411 debug(F101,"rlogin ttinc errno","",errno);
7412 /* printf("Network error: %d\n", errno); */
7413 return(-1);
7414 }
7415 }
7416 return(0);
7417 }
7418
7419 /* two control messages are defined:
7420
7421 a double flag byte of 'o' indicates a one-byte message which is
7422 identical to what was once carried out of band.
7423
7424 a double flag byte of 'q' indicates a zero-byte message. This
7425 message is interpreted as two \377 data bytes. This is just a
7426 quote rule so that binary data from the server does not confuse the
7427 client. */
7428
7429 int
rlog_ctrl(cp,n)7430 rlog_ctrl(cp, n)
7431 unsigned char *cp;
7432 int n;
7433 {
7434 if ((n >= 5) && (cp[2] == 'o') && (cp[3] == 'o')) {
7435 if (rlog_oob(&cp[4],1))
7436 return(-5);
7437 return(5);
7438 } else if ((n >= 4) && (cp[2] == 'q') && (cp[3] == 'q')) {
7439 /* this is somewhat of a hack */
7440 cp[2] = '\377';
7441 cp[3] = '\377';
7442 return(2);
7443 }
7444 return(0);
7445 }
7446
7447 static int
rlog_oob(oobdata,count)7448 rlog_oob(oobdata, count) CHAR * oobdata; int count; {
7449 int i;
7450 int flush = 0;
7451
7452 debug(F111,"rlogin out_of_band","count",count);
7453
7454 for (i = 0; i<count; i++) {
7455 debug(F101,"rlogin out_of_band","",oobdata[i]);
7456 if (oobdata[i] & 0x01)
7457 continue;
7458
7459 if (oobdata[i] & 0x02) { /* Flush Buffered Data not yet displayed */
7460 debug(F101,"rlogin Flush Buffered Data command","",oobdata[i]);
7461
7462 /* Only flush the data if in fact we are in a mode that won't */
7463 /* get out of sync. Ie, not when we are in protocol mode. */
7464 switch ( what ) {
7465 case W_NOTHING:
7466 case W_CONNECT:
7467 case W_COMMAND:
7468 if ( rlog_inband )
7469 flush = 1;
7470 else
7471 ttflui();
7472 break;
7473 }
7474 }
7475 if (oobdata[i] & 0x10) { /* Switch to RAW mode */
7476 debug(F101,"rlogin Raw Mode command","",oobdata[i]);
7477 rlog_mode = RL_RAW;
7478 }
7479
7480 if (oobdata[i] & 0x20) { /* Switch to COOKED mode */
7481 debug(F101,"rlogin Cooked Mode command","",oobdata[i]);
7482 rlog_mode = RL_COOKED;
7483 }
7484 if (oobdata[i] & 0x80)
7485 { /* Send Window Size Info */
7486 debug(F101,"rlogin Window Size command","",oobdata[i]);
7487 /* Remember to send WS Info when Window Size changes */
7488 if ( !TELOPT_ME(TELOPT_NAWS) ) {
7489 TELOPT_ME(TELOPT_NAWS) = 1;
7490 rlog_naws();
7491 }
7492 }
7493 }
7494 return(flush);
7495 }
7496 #ifndef TCPIPLIB
7497 static SIGTYP
rlogoobh(sig)7498 rlogoobh(sig) int sig; {
7499 #ifdef SOLARIS
7500 char /* Or should it be char for all? */
7501 #else
7502 CHAR
7503 #endif /* SOLARIS */
7504 oobdata;
7505
7506 /* int count = 0; */ /* (not used) */
7507
7508 while (recv(ttyfd, &oobdata, 1, MSG_OOB) < 0) {
7509 /*
7510 * We need to do some special processing here.
7511 * Just in case the socket is blocked for input
7512 *
7513 */
7514 switch (errno) {
7515 case EWOULDBLOCK:
7516 break;
7517 default:
7518 return;
7519 }
7520 }
7521 debug(F101,"rlogin out_of_band","",oobdata);
7522 if (oobdata == 0x02) { /* Flush Buffered Data not yet displayed */
7523 debug(F101,"rlogin Flush Buffered Data command","",oobdata);
7524 netflui();
7525 }
7526 if (oobdata & 0x10) { /* Switch to raw mode */
7527 debug(F101,"rlogin Raw Mode command","",oobdata);
7528 rlog_mode = RL_RAW;
7529 }
7530 if (oobdata & 0x20) { /* Switch to cooked mode */
7531 debug(F101,"rlogin Cooked Mode command","",oobdata);
7532 rlog_mode = RL_COOKED;
7533 }
7534 if (oobdata & 0x80) { /* Send Window Size Info */
7535 debug(F101,"rlogin Window Size command","",oobdata);
7536 /* Remember to send WS Info when Window Size changes */
7537 if ( !TELOPT_ME(TELOPT_NAWS) ) {
7538 TELOPT_ME(TELOPT_NAWS) = 1;
7539 rlog_naws();
7540 }
7541 }
7542 }
7543 #endif /* TCPIPLIB */
7544 #endif /* RLOGCODE */
7545
7546 /* Send network BREAK */
7547 /*
7548 Returns -1 on error, 0 if nothing happens, 1 if BREAK sent successfully.
7549 */
7550 int
netbreak()7551 netbreak() {
7552 CHAR buf[3];
7553 if (ttnet == NET_TCPB) {
7554 if (ttnproto == NP_TELNET) {
7555 #ifdef TNCODE
7556 buf[0] = (CHAR) IAC; buf[1] = (CHAR) BREAK; buf[2] = (CHAR) 0;
7557 if (
7558 #ifdef OS2
7559 nettol((char *) buf, 2)
7560 #else
7561 ttol(buf, 2)
7562 #endif /* OS2 */
7563 < 2)
7564 return(-1);
7565 if (tn_deb || debses || deblog) {
7566 extern char tn_msg[];
7567 ckmakmsg(tn_msg,TN_MSG_LEN,"TELNET SENT ",TELCMD(BREAK),
7568 NULL,NULL);
7569 debug(F101,tn_msg,"",BREAK);
7570 if (debses || tn_deb) tn_debug(tn_msg);
7571 }
7572 return(1);
7573 #else
7574 debug(F100,"netbreak no TNCODE","",0);
7575 return(0);
7576 #endif /* TNCODE */
7577 }
7578 /* Insert other TCP/IP protocols here */
7579 }
7580 /* Insert other networks here */
7581 return(0);
7582 }
7583 #endif /* NETCONN */
7584
7585
7586 #ifdef NETCONN
7587 #ifdef SUNX25
7588 /*
7589 SunLink X.25 support by Marcello Frutig, Catholic University,
7590 Rio de Janeiro, Brazil, 1990.
7591 */
7592
7593 /* PAD X.3, X.28 and X.29 support */
7594
7595 static CHAR x29err[MAXPADPARMS+3] = { X29_ERROR, INVALID_PAD_PARM, '\0' };
7596
7597 /* Initialize PAD */
7598
7599 extern CHAR padparms[];
7600
7601 VOID
initpad()7602 initpad() {
7603 padparms[PAD_BREAK_CHARACTER] = 0; /* Break character */
7604 padparms[PAD_ESCAPE] = 1; /* Escape permitted */
7605 padparms[PAD_ECHO] = 1; /* Kermit PAD does echo */
7606 padparms[PAD_DATA_FORWARD_CHAR] = 2; /* forward character CR */
7607 padparms[PAD_DATA_FORWARD_TIMEOUT] = 0; /* no timeout forward condition */
7608 padparms[PAD_FLOW_CONTROL_BY_PAD] = 0; /* not used */
7609 padparms[PAD_SUPPRESSION_OF_SIGNALS] = 1; /* allow PAD service signals */
7610 padparms[PAD_BREAK_ACTION] = 21; /* brk action: INT pk + brk ind*/
7611 padparms[PAD_SUPPRESSION_OF_DATA] = 0; /* no supression of user data */
7612 padparms[PAD_PADDING_AFTER_CR] = 0; /* no padding after CR */
7613 padparms[PAD_LINE_FOLDING] = 0; /* no line fold */
7614 padparms[PAD_LINE_SPEED] = 0; /* line speed - don't care */
7615 padparms[PAD_FLOW_CONTROL_BY_USER] = 0; /* flow cont of PAD - not used */
7616 padparms[PAD_LF_AFTER_CR] = 0; /* no LF insertion after CR */
7617 padparms[PAD_PADDING_AFTER_LF] = 0; /* no padding after LF */
7618 padparms[PAD_EDITING] = 1; /* can edit */
7619 padparms[PAD_CHAR_DELETE_CHAR] = 8; /* character delete character */
7620 padparms[PAD_BUFFER_DELETE_CHAR] = 21; /* buffer delete character */
7621 padparms[PAD_BUFFER_DISPLAY_CHAR] = 18; /* buffer display character */
7622 }
7623
7624 /* Set PAD parameters */
7625
7626 VOID
setpad(s,n)7627 setpad(s,n) CHAR *s; int n; {
7628 int i;
7629 CHAR *ps = s;
7630
7631 if (n < 1) {
7632 initpad();
7633 } else {
7634 for (i = 0; i < n; i++) {
7635 if (*ps > MAXPADPARMS)
7636 x29err[i+2] = *ps;
7637 else
7638 padparms[*ps] = *(ps+1);
7639 ps += 2;
7640 }
7641 }
7642 }
7643
7644 /* Read PAD parameters */
7645
7646 VOID
readpad(s,n,r)7647 readpad(s,n,r) CHAR *s; int n; CHAR *r; {
7648 int i;
7649 CHAR *ps = s;
7650 CHAR *pr = r;
7651
7652 *pr++ = X29_PARAMETER_INDICATION;
7653 if (n > 0) {
7654 for (i = 0; i < n; i++, ps++) {
7655 if (*ps > MAXPADPARMS) {
7656 x29err[i+2] = *ps++;
7657 } else {
7658 *pr++ = *ps;
7659 *pr++ = padparms[*ps++];
7660 }
7661 }
7662 } else {
7663 for (i = 1; i < MAXPADPARMS; i++) {
7664 *pr++ = i;
7665 *pr++ = padparms[i];
7666 }
7667 }
7668 }
7669
7670 int
qbitpkt(s,n)7671 qbitpkt(s,n) CHAR *s; int n; {
7672 CHAR *ps = s;
7673 int x29cmd = *ps;
7674 CHAR *psa = s+1;
7675 CHAR x29resp[(MAXPADPARMS*2)+1];
7676
7677 switch (x29cmd) {
7678
7679 case X29_SET_PARMS:
7680 setpad (ps+1,n/2);
7681 if ((int)strlen((char *)x29err) > 2) {
7682 ttol(x29err,(int)strlen((char *)x29err));
7683 x29err[2] = '\0';
7684 }
7685 return (-2);
7686 case X29_READ_PARMS:
7687 readpad (ps+1,n/2,x29resp);
7688 setqbit ();
7689 ttol(x29resp,(n>1)?(n+1):(2*MAXPADPARMS+1));
7690 if ((int)strlen((char *)x29err) > 2) {
7691 ttol(x29err,(int)strlen((char *)x29err));
7692 x29err[2] = '\0';
7693 }
7694 resetqbit();
7695 break;
7696 case X29_SET_AND_READ_PARMS:
7697 setpad (ps+1,n/2);
7698 readpad (ps+1,n/2,x29resp);
7699 setqbit();
7700 ttol(x29resp,(n>1)?(n+1):(2*MAXPADPARMS+1));
7701 if ((int)strlen((char *)x29err) > 2) {
7702 ttol (x29err,(int)strlen((char *)x29err));
7703 x29err [2] = '\0';
7704 }
7705 resetqbit();
7706 return (-2);
7707 case X29_INVITATION_TO_CLEAR:
7708 (VOID) x25clear();
7709 return (-1);
7710 case X29_INDICATION_OF_BREAK:
7711 break;
7712 }
7713 return (0);
7714 }
7715
7716 /* PAD break action processor */
7717
7718 VOID
breakact()7719 breakact() {
7720 extern char x25obuf[MAXOX25];
7721 extern int obufl;
7722 extern int active;
7723 extern unsigned char tosend;
7724 static CHAR indbrk[3] = {
7725 X29_INDICATION_OF_BREAK,
7726 PAD_SUPPRESSION_OF_DATA,
7727 1
7728 };
7729 CHAR intudat, cause, diag;
7730
7731 if (x25stat() < 0) return; /* Ignore if no virtual call established */
7732
7733 if (padparms[PAD_BREAK_ACTION] != 0) /* Forward condition */
7734 if (ttol((CHAR *)x25obuf,obufl) < 0) {
7735 perror ("\r\nCan't send characters");
7736 active = 0;
7737 } else {
7738 bzero (x25obuf,sizeof(x25obuf));
7739 obufl = 0;
7740 tosend = 0;
7741 };
7742
7743 switch (padparms[PAD_BREAK_ACTION]) {
7744
7745 case 0 : break; /* do nothing */
7746 case 1 : /* send interrupt packet with interrupt user data field = 1 */
7747 intudat = 1;
7748 x25intr (intudat);
7749 break;
7750 case 2 : /* send reset packet with cause and diag = 0 */
7751 cause = diag = 0;
7752 x25reset (cause,diag);
7753 break;
7754 case 5 : /* send interrupt packet with interrupt user data field = 0 */
7755 intudat = 0;
7756 x25intr (intudat);
7757 setqbit ();
7758 /* send indication of break without a parameter field */
7759 ttoc(X29_INDICATION_OF_BREAK);
7760 resetqbit ();
7761 break;
7762 case 8 : active = 0; /* leave data transfer */
7763 conol ("\r\n");
7764 break;
7765 case 21: /* send interrupt packet with interrupt user data field = 0 */
7766 intudat = 0;
7767 x25intr (intudat);
7768 setpad (indbrk+1,2); /* set pad to discard input */
7769 setqbit ();
7770 /* send indication of break with parameter field */
7771 ttol (indbrk,sizeof(indbrk));
7772 resetqbit ();
7773 break;
7774 }
7775 }
7776
7777 /* X.25 support functions */
7778
7779 X25_CAUSE_DIAG diag;
7780
7781 /*
7782 Convert a null-terminated string representing an X.121 address
7783 to a packed BCD form.
7784 */
7785 int
pkx121(str,bcd)7786 pkx121(str,bcd) char *str; CHAR *bcd; {
7787 int i, j;
7788 u_char c;
7789
7790 i = j = 0;
7791 while (str[i]) {
7792 if (i >= 15 || str [i] < '0' || str [i] > '9')
7793 return (-1);
7794 c = str [i] - '0';
7795 if (i & 1)
7796 bcd [j++] |= c;
7797 else
7798 bcd [j] = c << 4;
7799 i++;
7800 }
7801 return (i);
7802 }
7803
7804 /* Reads and prints X.25 diagnostic */
7805
7806 int
x25diag()7807 x25diag () {
7808 int i;
7809
7810 bzero ((char *)&diag,sizeof(diag));
7811 if (ioctl(ttyfd,X25_RD_CAUSE_DIAG,&diag)) {
7812 perror ("Reading X.25 diagnostic");
7813 return(-1);
7814 }
7815 if (diag.datalen > 0) {
7816 printf ("X.25 Diagnostic :");
7817 for (i = 0; i < (int)diag.datalen; i++)
7818 printf(" %02h",diag.data[i])+
7819 printf ("\r\n");
7820 }
7821 return(0);
7822 }
7823
7824 /* X.25 Out-of-Band Signal Handler */
7825
7826 SIGTYP
x25oobh(foo)7827 x25oobh(foo) int foo; {
7828 int oobtype;
7829 u_char oobdata;
7830 int t;
7831
7832 (VOID) signal(SIGURG,x25oobh);
7833 do {
7834 if (ioctl(ttyfd,X25_OOB_TYPE,&oobtype)) {
7835 perror ("Getting signal type");
7836 return;
7837 }
7838 switch (oobtype) {
7839 case INT_DATA:
7840 if (recv(ttyfd,(char *)&oobdata,1,MSG_OOB) < 0) {
7841 perror ("Receiving X.25 interrupt data");
7842 return;
7843 }
7844 t = oobdata;
7845 printf ("\r\nInterrupt received, data = %d\r\n", t);
7846 break;
7847 case VC_RESET:
7848 printf ("\r\nVirtual circuit reset\r\n");
7849 x25diag ();
7850 break;
7851 case N_RESETS:
7852 printf ("\r\nReset timeout\r\n");
7853 break;
7854 case N_CLEARS:
7855 printf ("\r\nClear timeout\r\n");
7856 break;
7857 case MSG_TOO_LONG:
7858 printf ("\r\nMessage discarded, too long\r\n");
7859 break;
7860 default:
7861 if (oobtype) printf("\r\nUnknown oob type %d\r\n",oobtype);
7862 break;
7863 }
7864 } while (oobtype);
7865 }
7866
7867 /* Send a X.25 interrupt packet */
7868
7869 int
7870 #ifdef CK_ANSIC
x25intr(char intr)7871 x25intr(char intr)
7872 #else
7873 x25intr(intr) char intr;
7874 #endif /* CK_ANSIC */
7875 /* x25intr */ {
7876 if (send(ttyfd,&intr,1,MSG_OOB) < 0) return(-1);
7877 debug(F100,"X.25 intr","",0);
7878 return(0);
7879 }
7880
7881 /* Reset X.25 virtual circuit */
7882 int
7883 #ifdef CK_ANSIC
x25reset(char cause,char diagn)7884 x25reset(char cause, char diagn)
7885 #else
7886 x25reset(cause, diagn) char cause; char diagn;
7887 #endif /* CK_ANSIC */
7888 /* x25reset */ {
7889 bzero ((char *)&diag,sizeof(diag));
7890 diag.flags = 0;
7891 diag.datalen = 2;
7892 diag.data[0] = cause;
7893 diag.data[1] = diagn;
7894 if (ioctl(ttyfd,X25_WR_CAUSE_DIAG,&diag) < 0)
7895 return(-1);
7896 debug(F100,"X.25 reset","",0);
7897 return(0);
7898 }
7899
7900 /* Clear X.25 virtual circuit */
7901 int
x25clear()7902 x25clear() {
7903 int i;
7904 debug(F100,"X.25 clear","",0);
7905 bzero ((char *)&diag,sizeof(diag));
7906 diag.flags = (1 << DIAG_TYPE);
7907 diag.datalen = 2;
7908 diag.data[0] = 0;
7909 diag.data[1] = 0;
7910 ioctl (ttyfd,X25_WR_CAUSE_DIAG,&diag); /* Send Clear Request */
7911 return(ttclos(0)); /* Close socket */
7912 }
7913
7914 /* X.25 status */
7915 int
x25stat()7916 x25stat() {
7917 if (ttyfd == -1) return (-1);
7918 return(0);
7919 }
7920
7921 /* Set Q_BIT on */
7922 VOID
setqbit()7923 setqbit() {
7924 static int qbiton = 1 << Q_BIT;
7925 ioctl (ttyfd,X25_SEND_TYPE,&qbiton);
7926 }
7927
7928 /* Set Q_BIT off */
7929 VOID
resetqbit()7930 resetqbit() {
7931 static int qbitoff = 0;
7932 ioctl (ttyfd,X25_SEND_TYPE,&qbitoff);
7933 }
7934
7935 /* Read n characters from X.25 circuit into buf */
7936
7937 int
x25xin(n,buf)7938 x25xin(n,buf) int n; CHAR *buf; {
7939 register int x, c;
7940 int qpkt;
7941
7942 do {
7943 x = read(ttyfd,buf,n);
7944 if (buf[0] & (1 << Q_BIT)) { /* If Q_BIT packet, process it */
7945 /* If return -1 : invitation to clear; -2 : PAD changes */
7946 if ((c=qbitpkt(buf+1,x-2)) < 0) return(c);
7947 qpkt = 1;
7948 } else qpkt = 0;
7949 } while (qpkt);
7950
7951 #ifdef COMMENT /* Disabled by Stephen Riehm 19.12.97 */
7952 /* BUG!
7953 * if buf[] is full, then this null lands in nirvana!
7954 * I was unable to find any code which needs a trailing null in buf[]
7955 */
7956 if (x > 0) buf[x] = '\0';
7957 #endif /* COMMENT */
7958 if (x < 1) x = -1;
7959 debug(F101,"x25xin x","",x);
7960
7961 return(x);
7962 }
7963
7964 #ifdef COMMENT /* NO LONGER NEEDED! */
7965 /* X.25 read a line */
7966
7967 int
7968 #ifdef PARSENSE
7969 #ifdef CK_ANSIC
x25inl(CHAR * dest,int max,int timo,CHAR eol,CHAR start)7970 x25inl(CHAR *dest, int max,int timo, CHAR eol, CHAR start)
7971 #else
7972 x25inl(dest,max,timo,eol,start) int max,timo; CHAR *dest, eol, start;
7973 #endif /* CK_ANSIC */
7974 #else /* not PARSENSE */
7975 #ifdef CK_ANSIC
7976 x25inl(CHAR *dest, int max,int timo, CHAR eol)
7977 #else
7978 x25inl(dest,max,timo,eol) int max,timo; CHAR *dest, eol;
7979 #endif /* __SDTC__ */
7980 #endif /*PARSENSE */
7981 /* x25inl */ {
7982 CHAR *pdest;
7983 int pktype, goteol, rest, n;
7984 int i, flag = 0;
7985 extern int ttprty, ttpflg;
7986 int ttpmsk;
7987
7988 ttpmsk = (ttprty) ? 0177 : 0377; /* Set parity stripping mask */
7989
7990 debug(F101,"x25inl max","",max);
7991 debug(F101,"x25inl eol","",eol);
7992 pdest = dest;
7993 rest = max;
7994 goteol = 0;
7995 do {
7996 n = read(ttyfd,pdest,rest);
7997 n--;
7998 pktype = *pdest & 0x7f;
7999 switch (pktype) {
8000 case 1 << Q_BIT:
8001 if (qbitpkt(pdest+1,--n) < 0) return(-2);
8002 break;
8003 default:
8004 if (flag == 0) { /* if not in packet, search start */
8005 for (i = 1; (i < n) &&
8006 !(flag = ((dest[i] & 0x7f) == start));
8007 i++);
8008 if (flag == 0) { /* not found, discard junk */
8009 debug(F101,"x25inl skipping","",n);
8010 continue;
8011 } else { /* found, discard junk before start */
8012 int k;
8013 n = n - i + 1;
8014 for (k = 1; k <= n; k++, i++) dest[k] = dest[i];
8015 }
8016 }
8017 for (i = 0; (i < n) && /* search for eol */
8018 !(goteol=(((*pdest = *(pdest+1)&ttpmsk)&0x7f)== eol));
8019 i++,pdest++);
8020 *pdest = '\0';
8021 rest -= n;
8022 }
8023 } while ((rest > 0) && (!goteol));
8024
8025 if (goteol) {
8026 n = max - rest;
8027 debug (F111,"x25inl X.25 got",(char *) dest,n);
8028 if (timo) ttimoff();
8029 if (ttpflg++ == 0 && ttprty == 0) {
8030 if ((ttprty = parchk(dest,start,n)) > 0) {
8031 int j;
8032 debug(F101,"x25inl senses parity","",ttprty);
8033 debug(F110,"x25inl packet before",(char *)dest,0);
8034 ttpmsk = 0x7f;
8035 for (j = 0; j < n; j++)
8036 dest[j] &= 0x7f; /* Strip parity from packet */
8037 debug(F110,"x25inl packet after ",dest,0);
8038 } else {
8039 debug(F101,"parchk","",ttprty);
8040 if (ttprty < 0) { ttprty = 0; n = -1; }
8041 }
8042 }
8043 ttimoff();
8044 return(n);
8045 }
8046 ttimoff();
8047 return(-1);
8048 }
8049 #endif /* COMMENT */
8050 #endif /* SUNX25 */
8051
8052 #ifdef IBMX25
8053 /*
8054 * IBM X25 support - using the NPI streams interface
8055 * written by Stephen Riehm, pc-plus, Munich Germany
8056 */
8057
8058 /* riehm: missing functions / TODO list */
8059
8060 /*
8061 x25intr() - Send an interrupt packet
8062 */
8063
8064 /* return an error message depending on packet type */
8065 char *
x25err(n)8066 x25err(n) int n; {
8067 static char buf[30];
8068 switch (n) {
8069 case NBADADDR: return "invalid address";
8070 case NBADOPT: return "invalid options";
8071 case NACCESS: return "no permission";
8072 case NNOADDR: return "unable to allocate address";
8073 case NOUTSTATE: return "invalid state";
8074 case NBADSEQ: return "invalid sequence number";
8075 case NSYSERR: return "system error";
8076 case NBADDATA: return "invalid data size";
8077 case NBADFLAG: return "invalid flag";
8078 case NNOTSUPPORT: return "unsupported primitive";
8079 case NBOUND: return "address in use";
8080 case NBADQOSPARAM: return "bad QOS parameters";
8081 case NBADQOSTYPE: return "bad QOS type";
8082 case NBADTOKEN: return "bad token value";
8083 case NNOPROTOID: return "protocol id could not be allocated";
8084 case NODDCUD: return "odd length call user data";
8085 default:
8086 ckmakmsg(buf,sizeof(buf),"Unknown NPI error ",ckitoa(n),NULL,NULL);
8087 return buf;
8088 }
8089 }
8090
8091 /* turn a meaningless primitive number into a meaningful primitive name */
8092 char *
x25prim(n)8093 x25prim(n) int n; {
8094 static char buf[30];
8095 switch(n) {
8096 case N_BIND_ACK: return "N_BIND_ACK";
8097 case N_BIND_REQ: return "N_BIND_REQ";
8098 case N_CONN_CON: return "N_CONN_CON";
8099 case N_CONN_IND: return "N_CONN_IND";
8100 case N_CONN_REQ: return "N_CONN_REQ";
8101 case N_CONN_RES: return "N_CONN_RES";
8102 case N_DATACK_IND: return "N_DATAACK_IND";
8103 case N_DATACK_REQ: return "N_DATAACK_REQ";
8104 case N_DATA_IND: return "N_DATA_IND";
8105 case N_DATA_REQ: return "N_DATA_REQ";
8106 case N_DISCON_IND: return "N_DISCON_IND";
8107 case N_DISCON_REQ: return "N_DISCON_REQ";
8108 case N_ERROR_ACK: return "N_ERROR_ACK";
8109 case N_EXDATA_IND: return "N_EXDATA_IND";
8110 case N_EXDATA_REQ: return "N_EXDATA_REQ";
8111 case N_INFO_ACK: return "N_INFO_ACK";
8112 case N_INFO_REQ: return "N_INFO_REQ";
8113 case N_OK_ACK: return "N_OK_ACK";
8114 case N_OPTMGMT_REQ: return "N_OPTMGMT_REQ";
8115 case N_RESET_CON: return "N_RESET_CON";
8116 case N_RESET_IND: return "N_RESET_IND";
8117 case N_RESET_REQ: return "N_RESET_REQ";
8118 case N_RESET_RES: return "N_RESET_RES";
8119 case N_UDERROR_IND: return "N_UDERROR_IND";
8120 case N_UNBIND_REQ: return "N_UNBIND_REQ";
8121 case N_UNITDATA_REQ: return "N_UNITDATA_REQ";
8122 case N_UNITDATA_IND: return "N_UNITDATA_IND";
8123 default:
8124 ckmakmsg(buf,sizeof(buf),"UNKNOWN (",ckitoa(n),")",NULL);
8125 return buf;
8126 }
8127 }
8128
8129 /*****************************************************************************
8130 * Function: x25getmsg()
8131 * Description: get a STREAMS message, and check it for errors
8132 *
8133 * Parameters:
8134 * fd - file descriptor to x25 device (opened)
8135 * control - control buffer (pre-allocated)
8136 * ctl_size - size of control buffer
8137 * data - data buffer (pre-allocated)
8138 * data_size - size of data buffer
8139 * flags - flags for getmsg()
8140 * expected - expected Primitive type
8141 *
8142 * Return Value:
8143 * >= 0 OK (size of data returned)
8144 * -1 error
8145 *
8146 */
8147 int
x25getmsg(fd,control,ctl_size,data,data_size,get_flags,expected)8148 x25getmsg( fd, control, ctl_size, data, data_size, get_flags, expected )
8149 int fd; /* X25 device (opened) */
8150 N_npi_ctl_t *control; /* control buffer (pre-allocated) */
8151 int ctl_size; /* size of control buffer */
8152 N_npi_data_t *data; /* data buffer (pre-allocated) */
8153 int data_size; /* size of data buffer */
8154 int *get_flags; /* getmsg() flags */
8155 int expected; /* expected primitive type */
8156 /* x25getmsg */ {
8157 int rc = 0; /* return code */
8158 struct strbuf *get_ctl=NULL; /* getmsg control */
8159 struct strbuf *get_data=NULL; /* getmsg data */
8160 int more = 0; /* flag for more data etc */
8161 int file_status = -1; /* file async status */
8162 N_npi_ctl_t * result; /* pointer to simplify switch() */
8163 int packet_type = -1; /* unknown packet thus far */
8164
8165 #ifdef TRACE
8166 printf( "TRACE: entering x25getmsg\n" );
8167 #endif /* TRACE */
8168
8169 debug( F110, "x25getmsg waiting for packet ", x25prim( expected ), 0);
8170 /* prepare the control structures for getmsg */
8171 if (control) {
8172 if ((get_ctl = (struct strbuf*)malloc(sizeof(struct strbuf))) == NULL)
8173 {
8174 perror("kermit x25getmsg(): get_ctl malloc failed\n");
8175 debug( F100, "x25getmsg malloc failed for get_ctl\n", "", 0);
8176 return(-1);
8177 }
8178 /* allow getmsg to return an unexpected packet type (which may be
8179 * larger than the expected one)
8180 */
8181 get_ctl->maxlen = NPI_MAX_CTL;
8182 get_ctl->len = 0;
8183 get_ctl->buf = (char *)control;
8184 } else {
8185 printf(
8186 "kermit x25getmsg(): internal error. control buffer MUST be pre-allocated!\n"
8187 );
8188 debug(F100,"x25getmsg internal error. no buffer pre-allocated","",0);
8189 return( -1 );
8190 }
8191 if (data) {
8192 if ((get_data = (struct strbuf*)malloc(sizeof(struct strbuf))) == NULL)
8193 {
8194 perror("kermit x25getmsg(): get_data malloc failed\n");
8195 debug( F100, "x25getmsg malloc failed for get_data\n", "", 0);
8196 return(-1);
8197 }
8198 get_data->maxlen = (NPI_MAX_DATA < data_size ) ?
8199 NPI_MAX_DATA :
8200 data_size;
8201 get_data->len = 0;
8202 get_data->buf = (char *)data;
8203 }
8204
8205 /* get an X.25 packet -
8206 * it may be any kind of packet, so check for special cases
8207 * it may be split into multiple parts - so loop if necessary
8208 */
8209 do {
8210 #ifdef DEBUG
8211 printf( "kermit: x25getmsg(): getting a message\n" );
8212 #endif /* DEBUG */
8213 errno = 0;
8214 if ((more = getmsg(fd, get_ctl, get_data, get_flags)) < 0) {
8215 #ifdef DEBUG
8216 printf( "kermit: x25getmsg(): getmsg returned an error\n" );
8217 perror( "getmsg error was" );
8218 #endif /* DEBUG */
8219 debug(F101, "x25getmsg getmsg returned an error\n", "", errno);
8220 if ((errno == EAGAIN) && (get_data && (get_data->len > 0)) ) {
8221 /* was in non-blocking mode, nothing to get, but we're
8222 * already waiting for the rest of the packet -
8223 * switch to blocking mode for the next read.
8224 * file_status used to reset file status before returning
8225 */
8226 if ((file_status = fcntl(fd, F_GETFL, 0)) < 0
8227 || fcntl(fd, F_SETFL, file_status & ~O_NDELAY) < 0)
8228 {
8229 perror("x25getmsg(): couldn't change x25 blocking mode");
8230 debug(F101,
8231 "x25getmsg fcntl returned an error\n", "", errno);
8232 /* netclos(); */
8233 rc = -1;
8234 break;
8235 } else {
8236 /* loop again into a blocking getmsg() */
8237 continue;
8238 }
8239 } else {
8240 /* no data to get in non-blocking mode - return empty handed */
8241 perror( "x25getmsg(): getmsg failed" );
8242 debug(F101,"x25getmsg getmsg returned an error\n", "", errno);
8243 rc = -1;
8244 break;
8245 }
8246 } else if (more & MORECTL) {
8247 /* panic - the control information was larger than the
8248 * maximum control buffer size!
8249 */
8250 /* riehm: close connection? */
8251 #ifdef DEBUG
8252 printf("x25getmsg(): received partial control packet - panic\n");
8253 #endif /* DEBUG */
8254 debug( F101, "x25getmsg getmsg bad control block\n", "", errno);
8255 rc = -1;
8256 break;
8257 }
8258
8259 if (result = (N_npi_ctl_t *)control) {
8260 packet_type = result->bind_ack.PRIM_type;
8261 if (packet_type != N_OK_ACK) {
8262 x25lastmsg = packet_type;
8263 }
8264 }
8265 #ifdef DEBUG
8266 /* printf( "kermit: x25getmsg(): getting " ); */
8267 if (get_ctl->len > 0) {
8268 x25dump_prim(result);
8269 }
8270 debug(F110,
8271 "x25getmsg got packet ",
8272 x25prim( result->bind_ack.PRIM_type ),
8273 0
8274 );
8275 #endif /* DEBUG */
8276
8277 if (get_ctl->len >= (int)sizeof(result->bind_ack.PRIM_type)) {
8278 /* not as pretty as a switch(), but switch can't handle
8279 * runtime variable values :-(
8280 */
8281 if (packet_type == expected ) {
8282 /* got what we wanted, special case for DATA_IND
8283 * packets though */
8284 /* riehm: check Q-bit ? */
8285 #ifdef DEBUG
8286 printf("x25getmsg(): got expected packet\nrc is %d\n", rc);
8287 #endif /* DEBUG */
8288 if (packet_type == N_DATA_IND ) {
8289 /* data received. May be incomplete, even though
8290 * getmsg returned OK
8291 */
8292 if (result->data_ind.DATA_xfer_flags & N_MORE_DATA_FLAG)
8293 more |= MOREDATA;
8294 if (result->data_ind.DATA_xfer_flags & N_RC_FLAG)
8295 printf( "x25getmsg(): data packet wants ack\n" );
8296 }
8297 } else if( packet_type == N_DISCON_IND) {
8298 printf( "X25 diconnected\n" );
8299 /* riehm: need to acknowledge a disconnection? */
8300 x25clear();
8301 /* x25unbind( ttyfd ); */
8302 rc = -1;
8303 } else if( packet_type == N_ERROR_ACK) {
8304 errno = result->error_ack.UNIX_error;
8305 perror( "X25 error received" );
8306 rc = -1;
8307 } else {
8308 printf("x25getmsg(): failed %s\n", x25err(packet_type));
8309 rc = -1;
8310 }
8311 }
8312 #ifdef COMMENT
8313 else {
8314 /* Panic - no control data */
8315 printf( "kermit: x25getmsg(): no control data with packet\n" );
8316 rc = -1;
8317 }
8318 #endif /* COMMENT */
8319
8320 if (get_data && (get_data->len >= 0)) {
8321 get_data->buf += get_data->len;
8322 get_data->maxlen -= get_data->len;
8323 }
8324 } while ((rc == 0)
8325 && (get_data && (get_data->maxlen > 0))
8326 && (more & MOREDATA)
8327 );
8328
8329 /* return the file status to its original value, unless its still
8330 * set to -1, or one of the fcntl's failed */
8331 if ((file_status >= 0) && fcntl(fd, F_SETFL, file_status) < 0)
8332 rc = -1;
8333
8334 /*
8335 * Verify that we received an expected primitive
8336 * there is apparantly an error case where the primitive is set
8337 * correctly, but there is not enough data in the control structure
8338 */
8339 if ((packet_type != expected) && (get_ctl->len >= ctl_size) ) {
8340 fprintf(stderr,
8341 "x25getmsg(): %s NOT received. Primitive received was %s\n",
8342 x25prim( expected ), x25prim( packet_type ));
8343 debug(F110, "x25getmsg got an unexpected packet ",
8344 x25prim(packet_type),
8345 0
8346 );
8347 rc = -1;
8348 }
8349
8350 if (rc == 0) {
8351 if (get_data && ( get_data->len >= 0)) {
8352 rc = get_data->len;
8353 }
8354 }
8355
8356 if (get_ctl) { free(get_ctl); get_ctl = NULL; }
8357 if (get_data) { free(get_data); get_data = NULL; }
8358
8359 #ifdef COMMENT
8360 #ifdef DEBUG
8361 printf( "kermit x25getmsg(): returning %d\n", rc );
8362 #endif /* DEBUG */
8363 #endif /* COMMENT */
8364 debug(F110, "x25getmsg returning packet ", x25prim( packet_type ), 0);
8365
8366 #ifdef TRACE
8367 printf( "TRACE: leaving x25getmsg\n" );
8368 #endif /* TRACE */
8369 return(rc);
8370 }
8371
8372 /*****************************************************************************
8373 * Function: x25putmsg()
8374 *
8375 * Description:
8376 * send a message to a X25 STREAM
8377 *
8378 * Parameters:
8379 * fd - file descriptor to x25 device (opened)
8380 * control - control buffer (pre-allocated)
8381 * data - data buffer (pre-allocated)
8382 * data_len - length of data to be transmitted
8383 * put_flags - flags for putmsg()
8384 *
8385 * Return Value:
8386 * >= 0 number of bytes transmitted
8387 * -1 error
8388 */
8389 int
x25putmsg(fd,control,data,data_len,put_flags)8390 x25putmsg(fd, control, data, data_len, put_flags)
8391 int fd; /* X25 device (opened) */
8392 N_npi_ctl_t *control; /* control buffer (pre-allocated) */
8393 N_npi_data_t *data; /* data buffer (pre-allocated) */
8394 int data_len; /* length of data (not the size of
8395 the buffer) */
8396 int *put_flags; /* putmsg() flags */
8397 /* x25putmsg */ {
8398 int rc = 0; /* return code */
8399 ulong type; /* primitive type */
8400 struct strbuf *put_ctl = NULL; /* putmsg control */
8401 struct strbuf *put_data = NULL; /* putmsg data */
8402
8403 #ifdef TRACE
8404 printf( "TRACE: entering x25putmsg\n" );
8405 #endif /* TRACE */
8406
8407 #ifdef DEBUG
8408 printf( "kermit: x25putmsg(): putting " );
8409 x25dump_prim( control );
8410 printf( "\tdata:\t\t" );
8411 x25dump_data( data, 0, data_len );
8412 debug(F110,"x25putmsg: putting packet ",x25prim(control->PRIM_type),0);
8413 #endif /* DEBUG */
8414
8415 if (control) {
8416 put_ctl = (struct strbuf *)malloc( sizeof( struct strbuf ) );
8417 if (put_ctl == NULL) {
8418 perror("kermit x25putmsg(): put_ctl malloc failed\n");
8419 return(-1);
8420 }
8421 put_ctl->maxlen = 0; /* unused by putmsg */
8422 put_ctl->len = NPI_MAX_CTL;
8423 put_ctl->buf = (char *)control;
8424 }
8425 if (data && ( data_len > 0)) {
8426 put_data = (struct strbuf *)malloc( sizeof( struct strbuf ) );
8427 if( put_data == NULL) {
8428 perror("kermit x25putmsg(): put_data malloc failed\n");
8429 return(-1);
8430 }
8431 put_data->maxlen = 0; /* unused by putmsg */
8432 put_data->len = data_len;
8433 put_data->buf = (char *)data;
8434 }
8435
8436 errno = 0;
8437 rc = putmsg (fd, put_ctl, put_data, 0);
8438 if (rc < 0) {
8439 printf("x25putmsg(): couldn't put %s\n",x25prim(control->PRIM_type));
8440 perror("kermit: x25putmsg(): putmsg failed");
8441 return(-1);
8442 }
8443
8444 /* riehm: this should perhaps be discounted! */
8445 x25lastmsg = control->PRIM_type;
8446
8447 #ifdef COMMENT
8448 #ifdef DEBUG
8449 printf( "kermit debug: x25putmsg() returning %d\n", data_len );
8450 #endif /* DEBUG */
8451 #endif /* COMMENT */
8452 debug( F101, "x25putmsg block size put ", "", data_len);
8453
8454 #ifdef TRACE
8455 printf( "TRACE: leaving x25putmsg\n" );
8456 #endif /* TRACE */
8457
8458 return( data_len );
8459 }
8460
8461 /*****************************************************************************
8462 * Function: x25bind
8463 * Description: The bind submitted to NPI provides the information required
8464 * by the packet layer for it to listen for suitable incoming
8465 * calls.
8466 *
8467 * WARNING:
8468 *
8469 * This routine needs to be called in a completely different manner for
8470 * the client and server side. When starting a client, the
8471 * num_waiting_calls and CUD information should all be set to 0! The
8472 * client's CUD must be inserted in the CONN_REQ data block.
8473 * When starting a server, the CUD must be set to a CUD pattern, and
8474 * the number of waiting calls should be set to a number other than 0.
8475 * (num waiting calls is the number of incomming calls which are to be
8476 * put on hold while the server is servicing another client.)
8477 *
8478 * Who invented this crap?
8479 *
8480 * Parameters:
8481 * fd - X25 device (opened)
8482 * addr - local address
8483 * cud - User Data (null terminated)
8484 * cud_len - User Data length
8485 * num_waiting_calls - number of outstanding calls allowed on this stream
8486 * line - logical port number (1)
8487 * flags - 0, DEFAULT_LISTENER or TOKEN_REQUEST
8488 *
8489 * Return Value:
8490 * if binding is successful, 0 is returned for a client, and a token is
8491 * returned for a server
8492 *
8493 * Return code: 0 if successful
8494 * -1 if unsuccessful
8495 *****************************************************************************/
8496
8497 ulong
x25bind(fd,addr,cud,cud_len,num_waiting_calls,line,bind_flags)8498 x25bind(fd, addr, cud, cud_len, num_waiting_calls, line, bind_flags)
8499 int fd; /* X25 device (opened) */
8500 char * addr; /* local address */
8501 char * cud; /* Call User Data (null terminated) */
8502 int cud_len; /* User Data length */
8503 int num_waiting_calls; /* Outstanding calls allowed */
8504 int line; /* logical port number */
8505 ulong bind_flags; /* 0, DEFAULT_LISTENER or TOKEN_REQUEST */
8506 /* x25bind */ {
8507 ulong rc; /* return code */
8508 int get_flags; /* priority flag passed to getmsg */
8509 int put_flags = 0; /* output flags for putmsg, always 0 */
8510 ulong type; /* primitive type */
8511 N_bind_req_t *bind_req; /* pointer to N_BIND_REQ primitive */
8512 N_bind_ack_t *bind_ack; /* pointer to N_BIND_ACK primitive */
8513 char *addtl_info; /* pointer to info in addition to
8514 * the N_BIND_REQ primitive that is
8515 * passed in the control structure
8516 * to putmsg */
8517 int addr_len = 0; /* length of address string */
8518 ulong bind_req_t_size; /* for debugging only */
8519
8520 #ifdef TRACE
8521 printf("TRACE: entering x25bind\n" );
8522 #endif /* TRACE */
8523
8524 #ifdef DEBUG
8525 printf("TRACE: x25bind( %d, %s, %s, %d, %d )\n",
8526 fd, addr, cud, line, bind_flags
8527 );
8528 #endif /* DEBUG */
8529
8530 /*
8531 * Allocate and zero out space to hold the control portion of the
8532 * message passed to putmsg. This will contain the N_BIND_REQ
8533 * primitive and any additional info required for that.
8534 *
8535 * Note: allocated space is the size of the union typedef
8536 * N_npi_ctl_t to allow the use fo the generic x25putmsg routine.
8537 */
8538 bind_req = (N_bind_req_t *) malloc(sizeof( N_npi_ctl_t));
8539 if (bind_req == NULL) {
8540 perror("kermit: x25bind(): bind_req malloc failed");
8541 debug(F100, "x25bind bind_req malloc failed", "", 0);
8542 return(-1);
8543 }
8544 bzero((char *)bind_req, sizeof(N_npi_ctl_t));
8545
8546 /* Build the Bind Request Primitive */
8547 bind_req->PRIM_type = (ulong) N_BIND_REQ;
8548
8549 /* Note that the address length is n+2 and NOT n. Two bytes MUST preceed
8550 * the actual address in an N_BIND_REQ. The first byte contains the
8551 * line number being used with this address, and the second byte is the
8552 * X.121 address prefix, which must be zero.
8553 */
8554 addr_len = strlen(addr);
8555 bind_req->ADDR_length = (ulong) (addr_len + 2);
8556 bind_req->ADDR_offset = (ulong)(sizeof(N_bind_req_t));
8557 bind_req->CONIND_number = (ulong)num_waiting_calls; /* server only */
8558 bind_req->BIND_flags = (ulong) bind_flags; /* 0 in client */
8559 bind_req->PROTOID_length = (ulong) cud_len; /* 0 in client */
8560 if (cud_len == 0) {
8561 bind_req->PROTOID_offset = (ulong) 0;
8562 } else {
8563 /* need to remember the trailing NULL in the address - not
8564 * counted in the address length
8565 */
8566 bind_req->PROTOID_offset
8567 = (ulong) (sizeof(N_bind_req_t) + bind_req->ADDR_length);
8568 }
8569
8570 /*
8571 * Now fill in the additional information required with this primitive
8572 * (address and protocol information (Call User Data))
8573 */
8574 addtl_info = (char *) ((void *)bind_req + bind_req->ADDR_offset);
8575 /*
8576 * The bitwise "&" ensures that the line number is only one byte long
8577 */
8578 *addtl_info++ = (char) line & 0xff;
8579 *addtl_info++ = (char) 0; /* X.121 format */
8580 bcopy( addr, addtl_info, addr_len ); /* include trailing null */
8581 addtl_info += addr_len;
8582 if (cud_len > 0)
8583 bcopy( cud, addtl_info, cud_len );
8584 /*
8585 * Call putmsg() to put the bind request message on the stream
8586 */
8587 if (x25putmsg(fd,
8588 (N_npi_ctl_t*)bind_req,
8589 (N_npi_data_t *)NULL,
8590 0,
8591 &put_flags
8592 ) < 0) {
8593 printf( "kermit: x25bind(): x25putmsg failed\n" );
8594 return(-1);
8595 }
8596
8597 /*
8598 * Allocate and zero out space for the N_BIND_ACK primitive
8599 */
8600 bind_ack = (N_bind_ack_t *) malloc(sizeof(N_npi_ctl_t));
8601 if (bind_ack == NULL){
8602 perror("kermit: x25bind(): bind_ack malloc failed");
8603 return(-1);
8604 }
8605 bzero(bind_ack, sizeof(N_npi_ctl_t));
8606 /*
8607 * Initialize the control structure and flag variable sent to getmsg
8608 */
8609 get_flags=0;
8610
8611 /* get the ACK for the bind */
8612 #ifdef DEBUG
8613 printf( "kermit: x25bind() trying to get a BIND_ACK\n" );
8614 #endif /* DEBUG */
8615 rc = (ulong)x25getmsg( fd, (N_npi_ctl_t*)bind_ack,
8616 (int)sizeof( N_bind_ack_t ), (N_npi_data_t*)NULL, 0, &get_flags,
8617 N_BIND_ACK );
8618
8619 /* turn quantitive return code into a qualitative one */
8620 if (rc > 0) rc = 0;
8621
8622 /* if all went well, get the token from the acknowledgement packet */
8623 if ((bind_flags & TOKEN_REQUEST ) && ( rc >= 0)) {
8624 rc = bind_ack->TOKEN_value;
8625 }
8626
8627 /* free up the memory we allocated earlier */
8628 free(bind_req);
8629 free(bind_ack);
8630
8631 #ifdef TRACE
8632 printf( "TRACE: leaving x25bind\n" );
8633 #endif /* TRACE */
8634
8635 return( rc );
8636 }
8637
8638 /*****************************************************************************
8639 * Function: x25call
8640 * Description: This routine builds and sends an N_CONN_REQ primitive, then
8641 * checks for an N_CONN_CON primitive in return.
8642 *
8643 * Parameters:
8644 * fd - file descriptor of stream
8645 * caddr - called address (remote address)
8646 *
8647 * Functions Referenced:
8648 * malloc()
8649 * bzero()
8650 * getmsg()
8651 * putmsg()
8652 *
8653 * Return code:
8654 * 0 - if successful
8655 * -1 if not successful
8656 *****************************************************************************/
8657 int
x25call(fd,remote_nua,cud)8658 x25call(fd, remote_nua, cud)
8659 int fd; /* X25 device (opened) */
8660 char * remote_nua; /* remote address to call */
8661 char * cud; /* call user data */
8662 /* x25call */ {
8663 int rc; /* return code */
8664 int flags; /* Connection flags */
8665 int get_flags; /* priority flags for getmsg */
8666 ulong type; /* primitive type */
8667 N_conn_req_t *connreq_ctl; /* pointer to N_CONN_REQ primitive */
8668 N_npi_data_t *connreq_data; /* pointer to N_CONN_REQ data (CUD) */
8669 int connreq_data_len; /* length of filled data buffer */
8670 N_conn_con_t *conncon_ctl; /* pointer to N_CONN_CON primitive */
8671 N_npi_data_t *conncon_data; /* pointer to any data associated with
8672 * the N_CONN_CON primitive */
8673 char *addtl_info; /* pointer to additional info needed
8674 * for N_CONN_REQ primitive */
8675 int addr_len; /* length of address */
8676
8677 #ifdef TRACE
8678 printf( "TRACE: entering x25call\n" );
8679 #endif /* TRACE */
8680
8681 #ifdef DEBUG
8682 printf( "x25call( %d, %s )\n", fd, remote_nua );
8683 printf( "connecting to %s on fd %d\n", remote_nua, fd );
8684 #endif /* DEBUG */
8685
8686 /*
8687 * Allocate and zero out space for the N_CONN_REQ primitive
8688 * use the size of the generic NPI primitive control buffer
8689 */
8690 connreq_ctl = (N_conn_req_t *) malloc(sizeof(N_npi_ctl_t));
8691 if (connreq_ctl == NULL){
8692 perror("kermit: x25call(): connreq_ctl malloc failed");
8693 return(-1);
8694 }
8695 bzero(connreq_ctl,sizeof(N_npi_ctl_t));
8696 /*
8697 * Build the Connection Request Primitive
8698 */
8699 flags = 0;
8700 connreq_ctl->PRIM_type = (ulong) N_CONN_REQ;
8701
8702 /* Note that the address length is nchai+1 and not n+2. The line number
8703 * is only passed with the address for the bind. The first byte of
8704 * the address for the N_CONN primitives contains the X.121
8705 * address prefix, which must be zero. The remaining bytes are the
8706 * address itself.
8707 */
8708 addr_len = strlen( remote_nua );
8709 connreq_ctl->DEST_length = (ulong) (addr_len + 1);
8710 connreq_ctl->DEST_offset = (ulong) sizeof(N_conn_req_t);
8711 /* connreq_ctl->CONN_flags = (ulong)EX_DATA_OPT | REC_CONF_OPT; */
8712 connreq_ctl->CONN_flags = (ulong) 0;
8713 connreq_ctl->QOS_length = (ulong) 0; /* unsupported in AIX 4.1 */
8714 connreq_ctl->QOS_offset = (ulong) 0; /* unsupported in AIX 4.1 */
8715
8716 addtl_info = (char *) ((void*)connreq_ctl + connreq_ctl->DEST_offset);
8717 *addtl_info++ = (char) 0; /* X.121 format */
8718 bcopy( remote_nua, addtl_info, addr_len );
8719
8720 /*
8721 * setup the data buffer for the connection request
8722 */
8723 connreq_data = (N_npi_data_t *) malloc(sizeof(N_npi_data_t));
8724 if (connreq_data == NULL){
8725 perror("kermit: x25call(): connreq_data malloc failed");
8726 return(-1);
8727 }
8728 bzero(connreq_data,sizeof(N_npi_data_t));
8729
8730 /* facility selection needs to be put in the front of connreq_data */
8731 connreq_data_len = 0;
8732 connreq_data_len += x25facilities( (char *)connreq_data );
8733 if (cud && *cud) {
8734 bcopy(cud,
8735 (char *)((char *)connreq_data + connreq_data_len),
8736 strlen(cud)
8737 );
8738 connreq_data_len += strlen( cud );
8739 }
8740
8741 /*
8742 * Call putmsg() to put the connection request message on the stream
8743 */
8744 rc = x25putmsg( fd, (N_npi_ctl_t*)connreq_ctl, connreq_data,
8745 connreq_data_len, &flags );
8746 if (rc < 0) {
8747 return(-1);
8748 }
8749
8750 /*
8751 * Allocate and zero out space for the N_CONN_CON primitive
8752 */
8753 if ((conncon_ctl = (N_conn_con_t *) malloc(sizeof(N_npi_ctl_t))) == NULL) {
8754 perror("kermit: x25call(): conncon_ctl malloc failed");
8755 return(-1);
8756 }
8757 bzero(conncon_ctl, sizeof(N_npi_ctl_t));
8758
8759 /*
8760 * Allocate and zero out space for any data associated with N_CONN_CON
8761 */
8762 if ( (conncon_data = (N_npi_data_t *) malloc(NPI_MAX_DATA)) == NULL) {
8763 perror("kermit: x25call(): conncon_data malloc failed");
8764 return(-1);
8765 }
8766 bzero(conncon_data, NPI_MAX_DATA);
8767
8768 /* Initialize and build the structures for getmsg */
8769 get_flags=0;
8770
8771 rc = x25getmsg( fd, (N_npi_ctl_t*)conncon_ctl, (int)sizeof( N_conn_con_t ),
8772 conncon_data, NPI_MAX_DATA, &get_flags, N_CONN_CON );
8773
8774 /* turn quantitive return code into a qualitative one */
8775 if (rc > 0) rc = 0;
8776
8777 /* Free the space that we no longer need */
8778 if (connreq_ctl) { free(connreq_ctl); connreq_ctl = NULL; }
8779 if (conncon_ctl) { free(conncon_ctl); conncon_ctl = NULL; }
8780 if (conncon_data) { free(conncon_data); conncon_data = NULL; }
8781
8782 #ifdef TRACE
8783 printf( "TRACE: leaving x25call\n" );
8784 #endif /* TRACE */
8785
8786 return(rc);
8787 }
8788
8789 /*****************************************************************************
8790 * Function: x25getcall
8791 *
8792 * Description: This routine checks for an incomming call, verified
8793 * that it is a CONNIND (connection indication) message, and then
8794 * accepts the call and returns the file descriptor of the new stream
8795 *
8796 * Parameters:
8797 * fd - file descriptor of listening stream
8798 *
8799 * Return Codes:
8800 * callfd - file descriptor of connected incomming call.
8801 * - set to -1 if an error occured
8802 *
8803 *****************************************************************************/
8804 int
x25getcall(fd)8805 x25getcall(fd) int fd; {
8806 int x25callfd; /* fd of incomming call */
8807 N_conn_ind_t *connind_ctl; /* connind controll buffer */
8808 N_npi_data_t *connind_data; /* connind data buffer */
8809 int get_flags; /* flags for getmsg */
8810 ulong flags; /* connection flags */
8811 int rc; /* return code */
8812
8813 extern x25addr_t remote_nua; /* remote X.25 addr global var */
8814
8815 #ifdef TRACE
8816 printf( "TRACE: entering x25getcall\n" );
8817 #endif /* TRACE */
8818
8819 /* allocate space for connection indication buffers */
8820 if ((connind_ctl = (N_conn_ind_t *)malloc(sizeof(N_npi_ctl_t))) == NULL) {
8821 perror("kermit: x25getcall(): connind_ctl malloc failed");
8822 return (-1);
8823 }
8824 bzero(connind_ctl, sizeof(N_npi_ctl_t));
8825
8826 if ((connind_data = (N_npi_data_t *)malloc(NPI_MAX_DATA)) == NULL) {
8827 perror("kermit: x25getcall(): connind_data malloc failed");
8828 return (-1);
8829 }
8830 bzero(connind_data, NPI_MAX_DATA);
8831
8832 /* initialise control structures */
8833 get_flags = 0;
8834
8835 /* call getmsg to check for a connection indication */
8836 if (x25getmsg(fd,
8837 (N_npi_ctl_t*)connind_ctl,
8838 (int)sizeof(N_conn_ind_t),
8839 connind_data,
8840 NPI_MAX_DATA,
8841 &get_flags,
8842 N_CONN_IND
8843 ) < 0) {
8844 #ifdef DEBUG
8845 printf( "x25getcall(): errno is: %d\n", errno );
8846 #endif /* DEBUG */
8847 perror ("x25getcall(): getmsg failed");
8848 return(-1);
8849 }
8850
8851 /* a connection indication was received
8852 * - pull it to bits and answer the call
8853 */
8854 x25seqno = connind_ctl->SEQ_number;
8855 flags = connind_ctl->CONN_flags;
8856 #ifdef DEBUG
8857 printf( "setting remote_nua to a new value due to incomming call\n" );
8858 #endif /* DEBUG */
8859 /*
8860 * no guarantee that the address is null terminated, ensure that
8861 * after copying that it is (assumption: remote_nua is longer than
8862 * the address + 1)
8863 */
8864 bzero(remote_nua, sizeof(remote_nua));
8865 /* note: connind_ctl contains a x121 address, which has a null as
8866 * the FIRST character - strip it off!
8867 */
8868 ckstrncpy(remote_nua,
8869 (char*)((char*)connind_ctl + connind_ctl->SRC_offset + 1),
8870 connind_ctl->SRC_length - 1
8871 );
8872 #ifdef DEBUG
8873 printf( "remote_nua set to new value of %s\n", remote_nua );
8874 #endif /* DEBUG */
8875
8876 /* errors handled by callee */
8877 x25callfd = x25accept(x25seqno, flags);
8878
8879 /* free the malloc'd buffers */
8880 if (connind_ctl) { free(connind_ctl); connind_ctl = NULL; }
8881 if (connind_data) { free(connind_data); connind_data = NULL; }
8882
8883 #ifdef TRACE
8884 printf( "TRACE: leaving x25getcall\n" );
8885 #endif /* TRACE */
8886
8887 /* return the file descriptor (or error if < 0) */
8888 return( x25callfd );
8889 }
8890
8891 /*****************************************************************************
8892 * Function: x25accept
8893 *
8894 * Description: accept an incomming call
8895 * This essentially means opening a new STREAM and sending
8896 * an acknowledge back to the caller.
8897 *
8898 * Parameters:
8899 * seqno - sequence number for acknowledgement
8900 * flags - flags passed to us by the caller
8901 *
8902 * Return Codes:
8903 * fd - file descriptor of new STREAM
8904 * set to -1 if an error occured
8905 *
8906 *****************************************************************************/
8907 int
x25accept(seqno,flags)8908 x25accept(seqno,flags)
8909 ulong seqno; /* connection sequence number */
8910 ulong flags; /* connection flags */
8911 /* x25accept */ {
8912 int x25callfd; /* fd for incomming call */
8913 int get_flags; /* priority flags for getmsg */
8914 int put_flags = 0; /* flags for putmsg, always 0 */
8915 int addr_len; /* length of local address */
8916 ulong token; /* connection token */
8917 N_conn_res_t *conn_res; /* N_CONN_RES primitive */
8918 N_ok_ack_t *ok_ack; /* N_OK_ACK primitive */
8919 char *addtl_info; /* temp pointer */
8920 int rc; /* temporary return code */
8921
8922 /* global variables from ckcmai.c */
8923 extern int revcall, closgr, cudata;
8924 extern char udata[];
8925 extern x25addr_t local_nua; /* local X.25 address */
8926 extern char x25name[]; /* x25 device name (sx25a0) */
8927 extern char x25dev[]; /* x25 device file /dev/x25pkt */
8928 extern int x25port; /* logical port to use */
8929 ulong bind_flags = 0; /* flags for binding the X25 stream */
8930
8931 #ifdef TRACE
8932 printf( "TRACE: entering x25accept\n" );
8933 #endif /* TRACE */
8934
8935 /* open a new packet level stream */
8936 if ((x25callfd = open(x25dev, O_RDWR)) < 0) {
8937 perror ("kermit: x25accept(): X.25 device open error");
8938 debug(F101,"x25accept() device open error","",errno);
8939 return(-1);
8940 }
8941
8942 /* push the NPI onto the STREAM */
8943 if (ioctl(x25callfd,I_PUSH,"npi") < 0) {
8944 perror( "kermit: x25accept(): couldn't push npi on the X25 stream" );
8945 debug(F101,"x25accept can't push npi on the X25 stream","",errno);
8946 return (-1);
8947 }
8948
8949 /* bind kermit server to the local X25 address */
8950 /* taken from /usr/samples/sx25/npi/npiserver.c (AIX 4) */
8951 bind_flags |= TOKEN_REQUEST;
8952 token = x25bind(x25callfd,local_nua,(char *)NULL,0,0,x25port,bind_flags);
8953 if (token < 0) {
8954 printf( "kermit: x25accept(): couldn't bind to local X25 address\n" );
8955 netclos();
8956 return(-1);
8957 }
8958
8959 /* allocate connection response primitive */
8960 if ((conn_res = (N_conn_res_t *)malloc( NPI_MAX_CTL )) == NULL) {
8961 perror("kermit: x25accept(): conn_res malloc failed");
8962 return (-1);
8963 }
8964 bzero((char *)conn_res, NPI_MAX_CTL);
8965
8966 /* setup connection response primitive */
8967 addr_len = strlen( local_nua );
8968 conn_res->PRIM_type = (ulong)N_CONN_RES;
8969 conn_res->TOKEN_value = token;
8970 /* note address length is n+1 to accomodate the X.121 address prefix */
8971 conn_res->RES_length = (ulong)(addr_len + 1);
8972 conn_res->RES_offset = (ulong)sizeof( N_conn_res_t );
8973 conn_res->SEQ_number = seqno;
8974 conn_res->CONN_flags = 0;
8975 conn_res->QOS_length = 0; /* unsupported - must be 0 (!?) */
8976 conn_res->QOS_offset = 0;
8977
8978 addtl_info = (char *)((char *)conn_res + conn_res->RES_offset);
8979 *addtl_info++ = (char)0; /* X.121 address prefix */
8980 bcopy( local_nua, addtl_info, addr_len );
8981
8982 /*
8983 * send off the connect response
8984 */
8985 if (x25putmsg(x25callfd,
8986 (N_npi_ctl_t*)conn_res,
8987 (N_npi_data_t *)NULL,
8988 0,
8989 &put_flags
8990 ) < 0 ) {
8991 perror("kermit: x25accept(): putmsg connect response failed");
8992 return(-1);
8993 }
8994
8995 /*
8996 * Allocate and zero out space for the OK_ACK primitive
8997 */
8998 if ((ok_ack = (N_ok_ack_t *) malloc(sizeof(N_npi_ctl_t))) == NULL) {
8999 perror("kermit: x25call(): ok_ack malloc failed");
9000 return(-1);
9001 }
9002 bzero(ok_ack, sizeof(N_npi_ctl_t));
9003
9004 /* Initialize and build the structures for getmsg */
9005 get_flags=0;
9006
9007 rc = (int)x25getmsg(x25callfd,
9008 (N_npi_ctl_t*)ok_ack,
9009 (int)sizeof(N_ok_ack_t),
9010 (N_npi_data_t*)NULL,
9011 0,
9012 &get_flags,
9013 N_OK_ACK
9014 );
9015 if (rc == 0) {
9016 /* sequence number is only for disconnecting when not connected !? */
9017 x25seqno = 0;
9018 }
9019
9020 /* free up malloc'ed buffer space */
9021 if (conn_res) { free(conn_res); conn_res = NULL; }
9022 if (ok_ack) { free(ok_ack); ok_ack = NULL; }
9023
9024 #ifdef TRACE
9025 printf( "TRACE: leaving x25accept\n" );
9026 #endif /* TRACE */
9027
9028 return( ( rc >= 0 ) ? x25callfd : -1 );
9029 }
9030
9031 /*****************************************************************************
9032 * Function: x25unbind
9033 *
9034 * Description: This subroutine builds and sends an unbind request and gets
9035 * the acknowledgement for it.
9036 *
9037 * Parameters:
9038 * fd - File descriptor of the stream
9039 *
9040 * Functions Referenced:
9041 * getmsg()
9042 * putmsg()
9043 * malloc()
9044 * bzero()
9045 *
9046 * Return code:
9047 * 0 - if successful
9048 * -1 - if not successful
9049 *****************************************************************************/
9050 int
x25unbind(fd)9051 x25unbind(fd) int fd; { /* X25 device (opened) */
9052 int rc; /* return code */
9053 int flags; /* bind flags */
9054 int get_flags; /* priority flag for getmsg */
9055 ulong type; /* primitive type */
9056 N_unbind_req_t *unbind_req; /* pointer to N_UNBIND_REQ */
9057 N_ok_ack_t *ok_ack; /* pointer to N_OK_ACK */
9058
9059 #ifdef TRACE
9060 printf( "TRACE: entering x25unbind\n" );
9061 #endif /* TRACE */
9062
9063 #ifdef DEBUG
9064 /* printf( "x25unbind( %d )\n", fd ); */
9065 #endif /* DEBUG */
9066 debug(F101,"x25unbind closing x25 connection #","",fd);
9067
9068 /* Allocate and zero out space to hold the N_UNBIND_REQ primitive */
9069 unbind_req = (N_unbind_req_t *) malloc(sizeof(N_npi_ctl_t));
9070 if (unbind_req == NULL) {
9071 perror("kermit: x25unbind(): unbind_req malloc failed");
9072 return(-1);
9073 }
9074 bzero(unbind_req, sizeof(N_npi_ctl_t));
9075
9076 /*
9077 * Build the Unbind Request Primitive
9078 */
9079 flags = 0;
9080 unbind_req->PRIM_type = (ulong) N_UNBIND_REQ;
9081
9082 /*
9083 * Call putmsg() to put the bind request message on the stream
9084 */
9085 if (x25putmsg(fd,
9086 (N_npi_ctl_t*)unbind_req,
9087 (N_npi_data_t *)NULL,
9088 0,
9089 &flags
9090 ) < 0) {
9091 perror ("kermit: x25unbind(): putmsg failed");
9092 return(-1);
9093 }
9094
9095 /* Allocate and Zero out space for the N_OK_ACK primitive */
9096 ok_ack = (N_ok_ack_t *) malloc(sizeof(N_npi_ctl_t));
9097 if (ok_ack == NULL) {
9098 perror("kermit x25unbind(): ok_ack malloc failed\n");
9099 return(-1);
9100 }
9101 bzero(ok_ack, sizeof(N_npi_ctl_t));
9102
9103 /* Initialize and build the control structure for getmsg */
9104 get_flags=0;
9105
9106 /* Call getmsg() to check for an acknowledgement */
9107 rc = x25getmsg(fd,
9108 (N_npi_ctl_t*)ok_ack,
9109 (int)sizeof(N_ok_ack_t),
9110 (N_npi_data_t*)NULL,
9111 0,
9112 &get_flags,
9113 N_OK_ACK
9114 );
9115 if (rc < 0) {
9116 perror ("kermit: x25unbind: getmsg failed");
9117 return(-1);
9118 }
9119
9120 /* Free up the space that we no longer need */
9121 if (unbind_req) { free(unbind_req); unbind_req = NULL; }
9122 if (ok_ack) { free(ok_ack); ok_ack = NULL; }
9123
9124 #ifdef TRACE
9125 printf( "TRACE: leaving x25unbind\n" );
9126 #endif /* TRACE */
9127
9128 return(0);
9129 }
9130
9131 /*****************************************************************************
9132 * Function: x25xin
9133 *
9134 * Description:
9135 * Read n characters from X.25 circuit into buf (AIX only)
9136 *
9137 * Parameters:
9138 * data_buf_len maximum size of data buffer
9139 * data_buf pointer to pre-allocated buffer space
9140 *
9141 * Return Value:
9142 * the number of characters actually read
9143 */
9144 int
x25xin(data_buf_len,data_buf)9145 x25xin(data_buf_len,data_buf) int data_buf_len; CHAR *data_buf; {
9146 struct strbuf getmsg_ctl; /* streams control structure */
9147 struct strbuf getmsg_data; /* streams data structure */
9148 int rc = 0; /* return code */
9149 int getmsg_flags; /* packet priority flags */
9150 char * ctl_buf; /* npi control buffer */
9151 N_npi_ctl_t * result; /* pointer to simplify switch() */
9152
9153 #ifdef TRACE
9154 printf( "TRACE: entering x25xin\n" );
9155 #endif /* TRACE */
9156
9157 /* ensure that no maximum's are overridden */
9158 data_buf_len = (NPI_MAX_DATA < data_buf_len) ? NPI_MAX_DATA : data_buf_len;
9159
9160 /* allocate space for packet control info */
9161 if ((ctl_buf = (char *)malloc(NPI_MAX_CTL)) == NULL) {
9162 perror( "kermit: x25xin(): ctl_buf malloc" );
9163 return(-1);
9164 }
9165 #ifdef COMMENT
9166 /* riehm: need zeroed buffer for getmsg? */
9167 bzero( ctl_buf, NPI_MAX_CTL );
9168 /* clear data buffer */
9169 bzero( data_buf, data_buf_len );
9170 #endif /* COMMENT */
9171
9172 getmsg_flags = 0; /* get the first packet available */
9173
9174 rc = x25getmsg(ttyfd,
9175 ctl_buf,
9176 NPI_MAX_CTL,
9177 data_buf,
9178 data_buf_len,
9179 &getmsg_flags,
9180 N_DATA_IND
9181 );
9182 #ifdef COMMENT
9183 #ifdef DEBUG
9184 if (rc >= 0) {
9185 printf( "kermit: x25xin(): got " );
9186 x25dump_data( data_buf, 0, rc );
9187 } else {
9188 printf( "x25xin(): attempt to get data resulted in an error\n" );
9189 }
9190 #endif /* DEBUG */
9191 #endif /* COMMENT */
9192
9193 /* free buffers */
9194 if (ctl_buf) { free(ctl_buf); ctl_buf = NULL; }
9195
9196 #ifdef TRACE
9197 printf( "TRACE: leaving x25xi\n" );
9198 #endif /* TRACE */
9199
9200 return(rc);
9201 }
9202
9203 /*****************************************************************************
9204 * Function: x25write
9205 *
9206 * Description:
9207 * write a block of characters to the X25 STREAM (AIX)
9208 *
9209 * Parameters:
9210 * fd file descriptor to write to
9211 * databuf buffer containing data to write
9212 * databufsize size of the buffer to write
9213 *
9214 * Return Value:
9215 * size the number of bytes actually transmitted
9216 */
9217 int
x25write(fd,databuf,databufsize)9218 x25write(fd, databuf, databufsize)
9219 int fd; /* X25 STREAMS file descriptor (ttyfd) */
9220 char *databuf; /* buffer to write */
9221 int databufsize; /* buffer size */
9222 /* x25write */ {
9223 N_data_req_t *data_req_ctl;
9224 int rc; /* return code (size transmitted) */
9225 int write_flags = 0; /* always 0 !? */
9226
9227 #ifdef TRACE
9228 printf( "TRACE: entering x25write\n" );
9229 #endif /* TRACE */
9230
9231 if ((data_req_ctl = (N_data_req_t *)malloc(NPI_MAX_CTL) ) == NULL) {
9232 perror( "kermit: x25write(): data_req_ctl malloc" );
9233 return(-1);
9234 }
9235 data_req_ctl->PRIM_type = N_DATA_REQ;
9236 data_req_ctl->DATA_xfer_flags = 0;
9237
9238 /* riehm: possible extension
9239 * possibly need to think about splitting up the data buffer
9240 * into multiple parts if databufsize > NPI_MAX_DATA
9241 */
9242
9243 #ifdef COMMENT
9244 #ifdef DEBUG
9245 printf( "kermit: x25write(): writing data to x25 stream\n" );
9246 printf( "\tdata:\t" );
9247 x25dump_data(databuf, 0, databufsize);
9248 #endif /* DEBUG */
9249 #endif /* COMMENT */
9250 rc = x25putmsg(fd,
9251 (N_npi_ctl_t*)data_req_ctl,
9252 (N_npi_data_t*)databuf,
9253 databufsize,
9254 &write_flags
9255 );
9256 if (data_req) { free(data_req_ctl); data_req = NULL; }
9257
9258 #ifdef TRACE
9259 printf( "TRACE: leaving x25write\n" );
9260 #endif /* TRACE */
9261
9262 return(rc);
9263 }
9264
9265 /*****************************************************************************
9266 * Function: x25local_nua
9267 *
9268 * Description:
9269 * This routine is only interesting for IBM computers. In order
9270 * to set up a connection (see x25bind()) you need to know the
9271 * local NUA (x25 address). Unfortunately, you need all this code
9272 * to find that out, I just hope this works for everyone else!
9273 *
9274 * Parameters:
9275 * a pre-allocated character buffer, long enough to hold an X.25 address
9276 * and the tailing null.
9277 *
9278 * Return Value:
9279 * the length of the address string.
9280 * 0 = error
9281 */
9282 int
x25local_nua(char * buf)9283 x25local_nua(char *buf) {
9284 struct CuAt *response; /* structure to fill with info from ODM */
9285 CLASS_SYMBOL retClass; /* ODM class */
9286 char query[64]; /* odm database query */
9287 int rc = 0; /* return value (length of local NUA) */
9288 extern char x25name[]; /* x25 device name (sx25a0) */
9289
9290 #ifdef TRACE
9291 printf( "TRACE: entering x25local_nua\n" );
9292 #endif /* TRACE */
9293
9294 /* set up query string */
9295 if (x25name[0] == '\0') {
9296 #ifdef DEBUG
9297 printf( "kermit: x25local_nua(): No x25 device set, trying sx25a0\n" );
9298 #endif /* DEBUG */
9299 strcpy( x25name, "sx25a0" );
9300 }
9301 ckmakmsg(query, sizeof(query), "name like ",x25name,
9302 " and attribute like local_nua");
9303
9304 /* initialise ODM database */
9305 odmerrno = 0;
9306 if (odm_initialize() == -1) {
9307 printf( "x25local_nua(): can't initialize ODM database");
9308 switch (odmerrno) {
9309 case ODMI_INVALID_PATH:
9310 printf( "invalid path\n" );
9311 break;
9312 case ODMI_MALLOC_ERR:
9313 printf( "malloc failed\n" );
9314 break;
9315 default:
9316 printf( "unknown error %d\nPlease call IBM\n", odmerrno );
9317 }
9318 return(rc);
9319 }
9320
9321 /* open the CuAt class */
9322 retClass = odm_open_class(CuAt_CLASS);
9323 if (((int)retClass) == -1) {
9324 printf( "kermit: x25local_nua(): can't open CuAt class in odm. " );
9325 switch (odmerrno) {
9326 case ODMI_CLASS_DNE:
9327 printf( "CuAt class doesn't exist\n" );
9328 break;
9329 case ODMI_CLASS_PERMS:
9330 printf( "permission to CuAt class file denied\n" );
9331 break;
9332 case ODMI_MAGICNO_ERR:
9333 printf( "CuAt is an invalid ODM object class\n" );
9334 break;
9335 case ODMI_OPEN_ERR:
9336 printf( "cannot open CuAt class - and don't know why!\n" );
9337 break;
9338 case ODMI_INVALID_PATH:
9339 printf( "invalid path\n" );
9340 break;
9341 case ODMI_TOOMANYCLASSES:
9342 printf( "too many object classes have been opened\n" );
9343 break;
9344 default:
9345 printf( "unknown error %d\nPlease call IBM\n", odmerrno );
9346 }
9347 return(rc);
9348 }
9349
9350 #ifdef DEBUG
9351 printf("retClass= %d\n", retClass);
9352 #endif /* DEBUG */
9353
9354 response = (struct CuAt *)odm_get_first( retClass, query, NULL );
9355 if (((int)response) == -1) {
9356 printf( "kermit: x25local_nua(): odm query failed " );
9357 switch (odmerrno) {
9358 case ODMI_BAD_CRIT: /* Programming error */
9359 printf( "bad search criteria\n" );
9360 break;
9361 case ODMI_CLASS_DNE:
9362 printf( "CuAt class doesn't exist\n" );
9363 break;
9364 case ODMI_CLASS_PERMS:
9365 printf( "permission to CuAt class file denied\n" );
9366 break;
9367 case ODMI_INTERNAL_ERR:
9368 printf("odm internal error\nPlease contact your administrator\n" );
9369 break;
9370 case ODMI_INVALID_CLXN:
9371 printf("CuAt is invalid or inconsistent odm class collection\n");
9372 break;
9373 case ODMI_INVALID_PATH:
9374 printf( "invalid path\n" );
9375 break;
9376 case ODMI_MAGICNO_ERR:
9377 printf( "CuAt is an invalid ODM object class\n" );
9378 break;
9379 case ODMI_MALLOC_ERR:
9380 printf( "malloc failed\n" );
9381 break;
9382 case ODMI_OPEN_ERR:
9383 printf( "cannot open CuAt class - and don't know why!\n" );
9384 break;
9385 case ODMI_TOOMANYCLASSES:
9386 printf( "too many object classes have been opened\n" );
9387 break;
9388 default:
9389 printf( "unknown error %d\nPlease call IBM\n", odmerrno );
9390 }
9391 return(rc);
9392 }
9393
9394 /* check for a meaningfull response */
9395 if (response != NULL) {
9396 if (response->value != NULL) {
9397 strcpy(buf, response->value);
9398 rc = strlen( buf );
9399 #ifdef DEBUG
9400 /*
9401 printf( "attribute name is: %s\n", (char *)response->attribute );
9402 printf( "I think my address is %s\n", (char*)response->value );
9403 */
9404 #endif /* DEBUG */
9405 } else {
9406 printf( "kermit: x25local_nua(): couldn't find the local NUA\n" );
9407 }
9408 } else {
9409 switch (odmerrno) {
9410 case ODMI_BAD_CRIT:
9411 printf( "Error: ODMI_BAD_CRIT - bad criteria\n" );
9412 break;
9413 case ODMI_CLASS_DNE:
9414 printf( "Error: ODMI_CLASS_DNE - class doesn't exist\n" );
9415 break;
9416 case ODMI_CLASS_PERMS:
9417 printf( "Error: ODMI_CLASS_PERMS - class permissions\n" );
9418 break;
9419 case ODMI_INTERNAL_ERR:
9420 printf( "Error: ODMI_INTERNAL_ERR - panic\n" );
9421 break;
9422 case ODMI_INVALID_CLXN:
9423 printf( "Error: ODMI_INVALID_CLXN - invalid collection\n" );
9424 break;
9425 case ODMI_INVALID_PATH:
9426 printf( "Error: ODMI_INVALID_PATH - invalid path - what path?\n" );
9427 break;
9428 case ODMI_MAGICNO_ERR:
9429 printf( "Error: ODMI_MAGICNO_ERR - invalid object magic\n" );
9430 break;
9431 case ODMI_MALLOC_ERR:
9432 printf( "Error: ODMI_MALLOC_ERR - malloc failed\n" );
9433 break;
9434 case ODMI_OPEN_ERR:
9435 printf( "Error: ODMI_OPEN_ERR - cannot open class\n" );
9436 break;
9437 case ODMI_TOOMANYCLASSES:
9438 printf( "Error: ODMI_TOOMANYCLASSES - too many classes\n" );
9439 break;
9440 default:
9441 printf( "Unknown error!\n" );
9442 }
9443 return(rc);
9444 }
9445
9446 /* close the database again */
9447 odm_close_class( retClass );
9448
9449 /* forget about ODM all together */
9450 odm_terminate();
9451
9452 #ifdef TRACE
9453 printf( "TRACE: leaving x25local_nua\n" );
9454 #endif /* TRACE */
9455
9456 debug(F110, "x25local_nua local address is ", buf, 0);
9457 return(rc);
9458 }
9459
9460 /*****************************************************************************
9461 * Function: x25facilities
9462 *
9463 * Description:
9464 * build up the facilities data packet for a connection request
9465 *
9466 * Parameters:
9467 * a pre-allocated char buffer, normally NPI_MAX_DATA big.
9468 *
9469 * Return Value:
9470 * the number of characters inserted into the buffer
9471 */
9472 int
x25facilities(buffer)9473 x25facilities(buffer) char *buffer; {
9474 extern int revcall;
9475 extern int closgr;
9476 char *p; /* temp pointer */
9477 char *start; /* temp pointer */
9478
9479 #ifdef TRACE
9480 printf( "TRACE: entering x25facilities\n" );
9481 #endif /* TRACE */
9482
9483 p = buffer + 1;
9484 start = p;
9485
9486 #ifdef DEBUG
9487 printf( "kermit: x25facilities(): getting X25 facilities\n" );
9488 #endif /* DEBUG */
9489
9490 if (revcall != 0) {
9491 #ifdef DEBUG
9492 printf("reverse charge: %d\n", revcall );
9493 #endif /* DEBUG */
9494 *++p = 0x01;
9495 *++p = revcall;
9496 }
9497 if (closgr > 0) {
9498 #ifdef DEBUG
9499 printf("closed user group: %d\n", closgr );
9500 #endif /* DEBUG */
9501 *++p = 0x03;
9502 *++p = closgr;
9503 }
9504
9505 #ifdef DEBUG
9506 if (p == start) {
9507 printf( "no facilities\n" );
9508 }
9509 #endif /* DEBUG */
9510
9511 /* set the size of the facilities buffer */
9512 *buffer = (char)( p - start ) & 0xff;
9513
9514 #ifdef DEBUG
9515 printf( "kermit: x25facilities(): returning %d\n", (int)(p - buffer) );
9516 #endif /* DEBUG */
9517
9518 #ifdef TRACE
9519 printf( "TRACE: leaving x25facilities\n" );
9520 #endif /* TRACE */
9521
9522 /* return the size of the facilities with size byte */
9523 /* 1 == no facilities, 0 byte returned as facilities size */
9524 return( (int)(p - buffer) );
9525 }
9526
9527 /*
9528 * reset the connection
9529 */
9530 int
x25reset(cause,diagn)9531 x25reset(cause, diagn) char cause; char diagn; {
9532 /* not implemented */
9533
9534 #ifdef TRACE
9535 printf( "TRACE: entering x25reset\n" );
9536 #endif /* TRACE */
9537
9538 #ifdef TRACE
9539 printf( "TRACE: leaving x25reset\n" );
9540 #endif /* TRACE */
9541
9542 return(0);
9543 }
9544
9545 /*
9546 * clear the x25 connection - ie: hang up
9547 */
9548 int
x25clear()9549 x25clear() {
9550 int get_flags = 0; /* priority flag for getmsg */
9551 int put_flags = 0; /* send flags, always 0 */
9552 ulong type; /* primitive type */
9553 N_discon_req_t *discon_req; /* pointer to N_DISCON_REQ */
9554 N_discon_ind_t *discon_ind; /* pointer to N_DISCON_IND */
9555 N_npi_data_t *discon_data; /* pointer to N_DISCON_IND data */
9556 int rc = 0; /* return code */
9557
9558 #ifdef TRACE
9559 printf( "TRACE: entering x25clear\n" );
9560 #endif /* TRACE */
9561
9562 #ifdef DEBUG
9563 /* printf( "x25clear(): checking last msg: %s\n", x25prim(x25lastmsg)); */
9564 #endif /* DEBUG */
9565
9566 /*
9567 * The following checks are used to ensure that we don't disconnect
9568 * or unbind twice - this seems to throw the NPI interface right out of
9569 * kilter.
9570 */
9571 switch(x25lastmsg) {
9572 case N_BIND_ACK:
9573 case N_CONN_CON:
9574 case N_CONN_REQ:
9575 case N_DATA_REQ:
9576 case N_DATA_IND:
9577 {
9578 #ifdef DEBUG
9579 /* printf("x25clear(): actively disconnecting\n"); */
9580 #endif /* DEBUG */
9581
9582 discon_req = (N_discon_req_t *)malloc(NPI_MAX_CTL);
9583 if (discon_req == NULL) {
9584 perror("kermit x25clear(): discon_req malloc failed\n");
9585 /* fallthrough, try to unbind the NPI anyway */
9586 } else {
9587 discon_req->PRIM_type = N_DISCON_REQ;
9588 discon_req->DISCON_reason = 0; /* not used by AIX */
9589 discon_req->RES_length = 0;
9590 discon_req->RES_offset = (ulong)(sizeof(N_discon_req_t));
9591 discon_req->SEQ_number = x25seqno; /* global */
9592
9593 if (x25putmsg(ttyfd,
9594 (N_npi_ctl_t*)discon_req,
9595 (N_npi_data_t*)NULL,
9596 0,
9597 &put_flags
9598 ) < 0) {
9599 perror("x25putmsg failed in x25clear()");
9600 }
9601 discon_ind = (N_discon_ind_t *)malloc(NPI_MAX_CTL);
9602 discon_data = (N_npi_data_t *)malloc(NPI_MAX_DATA);
9603 if((discon_ind == NULL) || (discon_data == NULL)) {
9604 perror("x25clear(): discon_ind malloc failed\n");
9605 /* fallthrough, try to unbind the NPI anyway */
9606 } else {
9607 if(x25getmsg(ttyfd,
9608 (N_npi_ctl_t*)discon_ind,
9609 NPI_MAX_CTL,
9610 (N_npi_data_t*)discon_data,
9611 NPI_MAX_DATA,
9612 &get_flags,
9613 N_OK_ACK
9614 ) < 0 ) {
9615 perror("x25getmsg failed in x25clear()");
9616 /* fallthrough, try to unbind the NPI anyway */
9617 }
9618 }
9619 }
9620 break;
9621 }
9622 }
9623
9624 if (x25lastmsg != N_UNBIND_REQ) {
9625 rc = x25unbind(ttyfd);
9626 }
9627
9628 #ifdef TRACE
9629 printf( "TRACE: leaving x25clear\n" );
9630 #endif /* TRACE */
9631
9632 return(rc);
9633 }
9634
9635 #ifdef DEBUG
9636 /*
9637 * only for debugging
9638 *
9639 * turn the internal representation of a datablock into something
9640 * half-way readable. Because the length is known, we can print
9641 * the string including null's etc (important, because the first(!)
9642 * byte of an X121 address is a null! (X121 addr == 0 + X25 addr)
9643 */
x25dump_data(char * addr,ulong offset,ulong length)9644 x25dump_data(char *addr, ulong offset, ulong length) {
9645 char *ptr = addr + offset;
9646 ulong i = length;
9647 /* allocate enough memory for all unprintable chars */
9648 char *buf = (char *)malloc( length * 4 );
9649 char *bptr = buf; /* pointer to current place in the print buffer */
9650
9651 while (i > 0) {
9652 if (isprint(*ptr)) {
9653 *bptr++ = *ptr;
9654 } else {
9655 *bptr++ = '[';
9656 strcpy(bptr,ckctox(*ptr,1)); bptr += 2;
9657 *bptr++ = ']';
9658 }
9659 ptr++;
9660 i--;
9661 }
9662 if (length > 0) {
9663 *bptr = '\0';
9664 printf( "%s", buf );
9665 }
9666 printf( " (%d+%d)\n", offset, length );
9667
9668 if (buf) { free(buf); buf = NULL; }
9669 return;
9670 }
9671
9672 /*
9673 * only for debugging
9674 * print as much useful information about a packet as possible
9675 */
x25dump_prim(primitive)9676 x25dump_prim(primitive) N_npi_ctl_t *primitive; {
9677 printf("Primitive");
9678 switch (primitive->PRIM_type) {
9679 case N_BIND_ACK:
9680 printf( "\tN_BIND_ACK\n\taddress:\t" );
9681 x25dump_data( (char *)primitive,
9682 primitive->bind_ack.ADDR_offset,
9683 primitive->bind_ack.ADDR_length );
9684 printf( "\tproto id:\t" );
9685 x25dump_data( (char *)primitive,
9686 primitive->bind_ack.PROTOID_offset,
9687 primitive->bind_ack.PROTOID_length );
9688 printf( "\tconnind:\t%d\n\ttoken:\t\t%d\n",
9689 primitive->bind_ack.CONIND_number,
9690 primitive->bind_ack.TOKEN_value );
9691 break;
9692
9693 case N_BIND_REQ:
9694 printf( "\tN_BIND_REQ\n\taddress:\t" );
9695 x25dump_data( (char *)primitive,
9696 primitive->bind_req.ADDR_offset,
9697 primitive->bind_req.ADDR_length );
9698 printf( "\tproto id:\t" );
9699 x25dump_data( (char *)primitive,
9700 primitive->bind_req.PROTOID_offset,
9701 primitive->bind_req.PROTOID_length );
9702 printf( "\tconnind:\t%d\n\tflags:\t\t%d\n",
9703 primitive->bind_req.CONIND_number,
9704 primitive->bind_req.BIND_flags );
9705 break;
9706
9707 case N_CONN_CON:
9708 printf( "\tN_CONN_CON\n" );
9709 printf( "\tRES\t\t" );
9710 x25dump_data( (char *)primitive,
9711 primitive->conn_con.RES_offset,
9712 primitive->conn_con.RES_length );
9713 printf( "\tflags:\t%d\n", primitive->conn_con.CONN_flags );
9714 break;
9715
9716 case N_CONN_IND:
9717 printf( "\tN_CONN_IND\n" );
9718 printf( "\tsource:\t\t" );
9719 x25dump_data( (char *)primitive,
9720 primitive->conn_ind.SRC_offset,
9721 primitive->conn_ind.SRC_length );
9722 printf( "\tdestination:\t" );
9723 x25dump_data( (char *)primitive,
9724 primitive->conn_ind.DEST_offset,
9725 primitive->conn_ind.DEST_length );
9726 printf( "\tSEQ_number:\t%d\n", primitive->conn_ind.SEQ_number );
9727 printf( "\tflags:\t%d\n", primitive->conn_ind.CONN_flags );
9728 break;
9729
9730 case N_CONN_REQ:
9731 printf( "\tN_CONN_REQ\n\tdestination:\t" );
9732 x25dump_data( (char *)primitive,
9733 primitive->conn_req.DEST_offset,
9734 primitive->conn_req.DEST_length );
9735 printf( "\tflags:\t%d\n", primitive->conn_req.CONN_flags );
9736 break;
9737
9738 case N_CONN_RES:
9739 printf( "\tN_CONN_RES\n" );
9740 printf( "\tTOKEN_value\t%d\n", primitive->conn_res.TOKEN_value );
9741 printf( "\tSEQ_number\t%d\n", primitive->conn_res.SEQ_number );
9742 printf( "\tCONN_flags\t%d\n", primitive->conn_res.CONN_flags );
9743 printf( "\tRES\t\t" );
9744 x25dump_data( (char *)primitive,
9745 primitive->conn_res.RES_offset,
9746 primitive->conn_res.RES_length );
9747 break;
9748
9749 case N_DATACK_IND:
9750 printf( "\tN_DATACK_IND\n" );
9751 break;
9752
9753 case N_DATACK_REQ:
9754 printf( "\tN_DATACK_REQ\n" );
9755 printf( "\tflags:\t%d\n", primitive->data_req.DATA_xfer_flags );
9756 break;
9757
9758 case N_DATA_IND:
9759 printf( "\tN_DATA_IND\n" );
9760 printf( "\tflags:\t%d\n", primitive->data_ind.DATA_xfer_flags );
9761 break;
9762
9763 case N_DATA_REQ:
9764 printf( "\tN_DATA_REQ\n" );
9765 break;
9766
9767 case N_DISCON_IND:
9768 printf( "\tN_DISCON_IND\n" );
9769 printf( "\torigin:\t%d\n", primitive->discon_ind.DISCON_orig );
9770 printf( "\treason:\t\t%d\n", primitive->discon_ind.DISCON_reason );
9771 printf( "\tseq no:\t\t%d\n", primitive->discon_ind.SEQ_number );
9772 printf( "\tRES:\t" );
9773 x25dump_data( (char *)primitive,
9774 primitive->discon_ind.RES_offset,
9775 primitive->discon_ind.RES_length );
9776 break;
9777
9778 case N_DISCON_REQ:
9779 printf( "\tN_DISCON_REQ\n" );
9780 printf( "\tDISCON_reason:\t%d\n",
9781 primitive->discon_req.DISCON_reason );
9782 printf( "\tRES:\t" );
9783 x25dump_data( (char *)primitive,
9784 primitive->discon_req.RES_offset,
9785 primitive->discon_req.RES_length );
9786 printf( "\tSEQ_number:\t%d\n", primitive->discon_req.SEQ_number );
9787 break;
9788
9789 case N_ERROR_ACK:
9790 printf( "\tN_ERROR_ACK\n" );
9791 printf( "\tCaused by:\t%s\n",
9792 x25prim( primitive->error_ack.ERROR_prim ) );
9793 printf( "\tNPI error:\t%s\n",
9794 x25err( primitive->error_ack.NPI_error ));
9795 errno = primitive->error_ack.UNIX_error;
9796 perror( "\t" );
9797 break;
9798
9799 case N_EXDATA_IND:
9800 printf( "\tN_EXDATA_ACK\n" );
9801 break;
9802
9803 case N_EXDATA_REQ:
9804 printf( "\tN_EXDATA_REQ\n" );
9805 break;
9806
9807 case N_INFO_ACK:
9808 printf( "\tN_INFO_ACK\n" );
9809 printf( "\tNSDU size:\t%d\n", primitive->info_ack.NSDU_size );
9810 printf( "\tENSDU size:\t%d\n", primitive->info_ack.ENSDU_size );
9811 printf( "\tCDATA size:\t%d\n", primitive->info_ack.CDATA_size );
9812 printf( "\tDDATA size:\t%d\n", primitive->info_ack.DDATA_size );
9813 printf( "\tADDR size:\t%d\n", primitive->info_ack.ADDR_size );
9814 printf( "\tNIDU size:\t%d\n", primitive->info_ack.NIDU_size );
9815 break;
9816
9817 case N_INFO_REQ:
9818 printf( "\tN_INFO_REQ\n" );
9819 break;
9820
9821 case N_OK_ACK:
9822 printf( "\tN_OK_ACK\n" );
9823 break;
9824
9825 case N_OPTMGMT_REQ:
9826 printf( "\tN_OPTMGMT_REQ\n" );
9827 break;
9828
9829 case N_RESET_CON:
9830 printf( "\tN_RESET_CON\n" );
9831 break;
9832
9833 case N_RESET_IND:
9834 printf( "\tN_RESET_IND\n" );
9835 printf( "\treason:\t\t%d\n", primitive->reset_ind.RESET_reason );
9836 printf( "\torigin:\t\t%d\n", primitive->reset_ind.RESET_orig );
9837 break;
9838
9839 case N_RESET_REQ:
9840 printf( "\tN_RESET_REQ\n" );
9841 printf( "\treason:\t\t%d\n", primitive->reset_req.RESET_reason );
9842 break;
9843
9844 case N_RESET_RES:
9845 printf( "\tN_RESET_RES\n" );
9846 break;
9847
9848 case N_UDERROR_IND:
9849 printf( "\tN_UDERROR_IND\n" );
9850 break;
9851
9852 case N_UNBIND_REQ:
9853 printf( "\tN_UNBIND_REQ\n" );
9854 break;
9855
9856 case N_UNITDATA_REQ:
9857 printf( "\tN_UNITDATA_REQ\n" );
9858 break;
9859
9860 case N_UNITDATA_IND:
9861 printf( "\tN_UNITDATA_IND\n" );
9862 break;
9863
9864 default:
9865 (void) printf( "Unknown NPI error %d", primitive->PRIM_type );
9866 return 0;
9867 }
9868 }
9869 #endif /* DEBUG */
9870
9871 /* it looks like signal handling is not needed with streams! */
9872 /* x25oobh() - handle SIGURG signals - take from isode ? */
9873
9874 #endif /* IBMX25 */
9875
9876 #ifndef NOHTTP
9877 /*
9878 Which time.h files to include... See ckcdeb.h for defaults.
9879 Note that 0, 1, 2, or all 3 of these can be included according to
9880 the symbol definitions.
9881 */
9882 #ifndef NOTIMEH
9883 #ifdef TIMEH
9884 #include <time.h>
9885 #endif /* TIMEH */
9886 #endif /* NOTIMEH */
9887
9888 #ifndef NOSYSTIMEH
9889 #ifdef SYSTIMEH
9890 #include <sys/time.h>
9891 #endif /* SYSTIMEH */
9892 #endif /* NOSYSTIMEH */
9893
9894 #ifndef NOSYSTIMEBH
9895 #ifdef SYSTIMEBH
9896 #include <sys/timeb.h>
9897 #endif /* SYSTIMEBH */
9898 #endif /* NOSYSTIMEBH */
9899
9900 #ifndef TIMEH
9901 #ifndef SYSTIMEH
9902 #ifndef SYSTIMEBH
9903 #ifdef Plan9
9904 #include <sys/time.h>
9905 #else
9906 #ifdef AIX41
9907 #include <time.h>
9908 #else
9909 #ifdef SUNOS4
9910 #include <sys/time.h>
9911 #else
9912 #ifdef SYSTIMEH
9913 #include <sys/time.h>
9914 #else
9915 #ifdef POSIX
9916 #include <posix/time.h>
9917 #else
9918 #ifdef CLIX
9919 #include <sys/time.h>
9920 #else
9921 #ifdef OS2
9922 #include <time.h>
9923 #else
9924 #include <time.h>
9925 /* #include <utime.h> */
9926 #endif /* OS2 */
9927 #endif /* CLIX */
9928 #endif /* POSIX */
9929 #endif /* SYSTIMEH */
9930 #endif /* SUNOS4 */
9931 #endif /* AIX41 */
9932 #endif /* Plan9 */
9933 #endif
9934 #endif
9935 #endif
9936
9937 #ifdef OS2
9938 #include <sys/utime.h>
9939 #ifdef NT
9940 #define utimbuf _utimbuf
9941 #endif /* NT */
9942 #define utime _utime
9943 #else
9944 #ifdef SYSUTIMEH /* <sys/utime.h> if requested, */
9945 #include <sys/utime.h> /* for extra fields required by */
9946 #else /* 88Open spec. */
9947 #ifdef UTIMEH /* or <utime.h> if requested */
9948 #include <utime.h> /* (SVR4, POSIX) */
9949 #define SYSUTIMEH /* Use this for both cases. */
9950 #endif /* UTIMEH */
9951 #endif /* SYSUTIMEH */
9952 #endif /* OS2 */
9953
9954 #ifdef VMS /* SMS 2007/02/15 */
9955 #include "ckvrtl.h"
9956 #endif /* def VMS */
9957
9958 #ifndef HTTP_VERSION
9959 #define HTTP_VERSION "HTTP/1.1"
9960 #endif /* HTTP_VERSION */
9961
9962 #ifdef CMDATE2TM
9963 time_t
9964 #ifdef CK_ANSIC
http_date(char * date)9965 http_date(char * date)
9966 #else
9967 http_date(date) char * date;
9968 #endif /* CK_ANSIC */
9969 /* http_date */ {
9970 /* HTTP dates are of the form: "Sun, 06 Oct 1997 20:11:47 GMT" */
9971 /* There are two older formats which we are required to parse
9972 * that we currently do not:
9973 *
9974 * RFC 850: "Sunday, 06-Oct-97 20:11:47 GMT"
9975 * asctime(): "Sun Nov 6 20:11:47 1997"
9976 *
9977 * However, it is required that all dates be sent in the form we
9978 * do accept. The other two formats are for compatibility with
9979 * really old servers.
9980 */
9981 extern char cmdatebuf[18];
9982 struct tm t_tm;
9983 time_t t;
9984 char ldate[32];
9985 int j;
9986
9987 j = ckindex(",",date,0,0,0);
9988 ckstrncpy(ldate,&date[j+1],25);
9989
9990 { /*
9991 cmcvtate() date changed to return a string pointer.
9992 fdc, 12 Aug 2001.
9993 */
9994 char * dp;
9995 dp = (char *)cmcvtdate(ldate,0); /* Convert to normal form */
9996 if (!dp)
9997 return(0);
9998 t_tm = *cmdate2tm(dp,1);
9999 }
10000 /*
10001 From Lucas Hart, 5 Dec 2001:
10002 "On the systems to which I have access (SunOS 4.1.1, Solaris 8, and Tru64),
10003 setting tm_isdst to -1 maintains the correct timezone offsets, i.e., writes
10004 the specified (GMT) time if the buffer size is 21, or the contemporaneous
10005 localtime if the buffer size is 25. Perhaps tm_isdst should be set in
10006 cmdate2tm(), rather than only in http_date."
10007 */
10008 #ifndef NOTM_ISDST /* For platforms where */
10009 t_tm.tm_isdst = -1; /* tm_isdst doesn't exist. */
10010 #endif /* NOTM_ISDST */
10011
10012 t = mktime(&t_tm); /* NOT PORTABLE */
10013
10014 #ifdef XX_TIMEZONE
10015 t -= _timezone;
10016 #endif /* XX_TIMEZONE */
10017
10018 return(t);
10019 }
10020 #endif /* CMDATE2TM */
10021
10022 char *
http_now()10023 http_now() {
10024 static char nowstr[32];
10025 #ifdef CMDATE2TM
10026 struct tm *gmt;
10027 time_t ltime; /* NOT PORTABLE */
10028
10029 time(<ime);
10030
10031 gmt = gmtime(<ime); /* PROBABLY NOT PORTABLE */
10032 strftime(nowstr,32,"%a, %d %b %Y %H:%M:%S GMT",gmt); /* NOT PORTABLE */
10033 /* not only is it not portable but it's locale-dependent */
10034 #else
10035 /*
10036 This is hopeless. First of all, it seems that HTTP wants Day and Month
10037 NAMES? In English? Whose idea was that? Even worse, the date/time must be
10038 expressed in Zulu (UTC (GMT)), and converting from local time to GMT is a
10039 nightmare. Every platform does it differently, if at all -- even if we
10040 restrict ourselves to UNIX. For example (quoting from recent C-Kermit edit
10041 history), "Fixed a longstanding bug in the BSDI version, in which incoming
10042 file dates were set in GMT rather than local time. It seems in 4.4BSD,
10043 localtime() does not return the local time, but rather Zero Meridian (Zulu)
10044 time (GMT), and must be adjusted by the tm_gmtoff value." Swell. For
10045 greater appreciation of the scope of the problem, just take a look at the
10046 time-related #ifdefs in ckutio.c. The only right way to do this is to add
10047 our own portable API for converting between local time and GMT/UTC/Zulu
10048 that shields us not only from UNIXisms like time_t and struct tm, but also
10049 the unbelievable amount of differences in time-related APIs -- e.g. is
10050 "timezone" an external variable or a function; which header file(s) do we
10051 include, etc etc etc. It's a major project.
10052 */
10053 int x;
10054 x = cmcvtdate("",1);
10055
10056 Evidently this code is not used -- if it is, it must be fixed to use
10057 new (aug 2001) cmcvtdate() calling conventions.
10058
10059 if (x < 0)
10060 return("");
10061 /* yyyymmdd hh:mm:ss */
10062 /* 01234567890123456 */
10063 nowstr[0] = 'X'; /* 1st letter of day */
10064 nowstr[1] = 'x'; /* 2nd letter of day */
10065 nowstr[2] = 'x'; /* 3rd letter of day */
10066 nowstr[3] = ',';
10067 nowstr[4] = ' ';
10068 nowstr[5] = cmdate[6];
10069 nowstr[6] = cmdate[7];
10070 nowstr[7] = ' ';
10071 nowstr[8] = ' '; /* first letter of month */
10072 nowstr[9] = ' '; /* second letter of month */
10073 nowstr[10] = ' '; /* third letter of month */
10074 nowstr[11] = ' ';
10075 nowstr[12] = cmdate[0];
10076 nowstr[13] = cmdate[1];
10077 nowstr[14] = cmdate[2];
10078 nowstr[15] = cmdate[3];
10079 nowstr[16] = ' ';
10080 nowstr[17] = cmdate[9];
10081 nowstr[18] = cmdate[10];
10082 nowstr[19] = cmdate[11];
10083 nowstr[20] = cmdate[12];
10084 nowstr[21] = cmdate[13];
10085 nowstr[22] = cmdate[14];
10086 nowstr[23] = cmdate[15];
10087 nowstr[24] = cmdate[16];
10088 nowstr[25] = ' ';
10089 nowstr[26] = 'G';
10090 nowstr[27] = 'M';
10091 nowstr[28] = 'T';
10092 nowstr[29] = '\0';
10093 #endif /* CMDATE2TM */
10094 return(nowstr);
10095 }
10096
10097 #ifndef OS2
10098 #ifndef CK_AUTHENTICATION
10099 /* from ckuusr.h, which this module normally doesn't include */
10100 _PROTOTYP( int dclarray, (char, int) );
10101 #endif /* CK_AUTHENTICATION */
10102 #endif /* OS2 */
10103 /*
10104 Assign http response pairs to given array.
10105 For best results, response pairs should contain no spaces.
10106
10107 Call with:
10108 resp = pointer to response list.
10109 n = size of response list.
10110 array = array letter.
10111 Returns:
10112 0 on failure.
10113 >= 1, size of array, on success.
10114 */
10115 static int
10116 #ifdef CK_ANSIC
http_mkarray(char ** resp,int n,char array)10117 http_mkarray(char ** resp, int n, char array)
10118 #else
10119 http_mkarray(resp, n, array) char ** resp; int n; char array;
10120 #endif /* CK_ANSIC */
10121 {
10122 #ifndef NOSPL
10123 int i, x;
10124 char ** ap;
10125 extern char ** a_ptr[];
10126 extern int a_dim[];
10127
10128 if (!array || n <= 0)
10129 return(0);
10130 if ((x = dclarray(array,n)) < 0) {
10131 printf("?Array declaration failure\n");
10132 return(-9);
10133 }
10134 /* Note: argument array is 0-based but Kermit array is 1-based */
10135 ap = a_ptr[x];
10136 ap[0] = NULL; /* 0th element is empty */
10137 for (i = 1; i <= n; i++) {
10138 ap[i] = resp[i-1]; /* If resp elements were malloc'd */
10139 resp[i-1] = NULL;
10140 }
10141 a_dim[x] = n;
10142 return(n);
10143 #else
10144 return(0);
10145 #endif /* NOSPL */
10146 }
10147
10148 #define HTTPHEADCNT 64
10149 int
http_get_chunk_len()10150 http_get_chunk_len()
10151 {
10152 int len = 0;
10153 int i = 0, j = -1;
10154 char buf[24];
10155 int ch;
10156
10157 while ((ch = http_inc(0)) >= 0 && i < 24) {
10158 buf[i] = ch;
10159 if ( buf[i] == ';' ) /* Find chunk-extension (if any) */
10160 j = i;
10161 if ( buf[i] == 10 ) { /* found end of line */
10162 if (i > 0 && buf[i-1] == 13)
10163 i--;
10164 buf[i] = '\0';
10165 break;
10166 }
10167 i++;
10168 }
10169 if ( i < 24 ) { /* buf now contains len in Hex */
10170 len = hextoulong(buf, j == -1 ? i : j-1);
10171 }
10172
10173 return(len);
10174 }
10175
10176 int
http_isconnected()10177 http_isconnected()
10178 {
10179 return(httpfd != -1);
10180 }
10181
10182 char *
http_host()10183 http_host()
10184 {
10185 return(httpfd != -1 ? http_host_port : "");
10186 }
10187
10188 char *
http_security()10189 http_security()
10190 {
10191 if ( httpfd == -1 )
10192 return("NULL");
10193 #ifdef CK_SSL
10194 if (tls_http_active_flag) {
10195 SSL_CIPHER * cipher;
10196 const char *cipher_list;
10197 static char buf[128];
10198 buf[0] = NUL;
10199 cipher = SSL_get_current_cipher(tls_http_con);
10200 cipher_list = SSL_CIPHER_get_name(cipher);
10201 SSL_CIPHER_description(cipher,buf,sizeof(buf));
10202 return(buf);
10203 }
10204 #endif /* CK_SSL */
10205 return("NULL");
10206 }
10207
10208 int
http_reopen()10209 http_reopen()
10210 {
10211 int rc = 0;
10212 char * s = NULL; /* strdup is not portable */
10213 if ( tcp_http_proxy ) {
10214 char * p;
10215 makestr(&s,(char *)http_host_port);
10216 p = s;
10217 while (*p != '\0' && *p != ':') p++; /* Look for colon */
10218 if (*p == ':') { /* Have a colon */
10219 *p++ = '\0'; /* Get service name or number */
10220 } else {
10221 p="http";
10222 }
10223 rc = http_open(s,p,http_ssl,NULL,0,http_agent);
10224 } else {
10225 makestr(&s,(char *)http_ip);
10226 rc = http_open(s,ckuitoa(http_port),http_ssl,NULL,0,http_agent);
10227 }
10228 free(s);
10229 return(rc);
10230 }
10231
10232
10233 int
10234 #ifdef CK_ANSIC
http_open(char * hostname,char * svcname,int use_ssl,char * rdns_name,int rdns_len,char * agent)10235 http_open(char * hostname, char * svcname, int use_ssl, char * rdns_name,
10236 int rdns_len, char * agent)
10237 #else /* CK_ANSIC */
10238 http_open(hostname, svcname, use_ssl, rdns_name, rdns_len, agent)
10239 char * hostname;
10240 char * svcname;
10241 int use_ssl;
10242 char * rdns_name;
10243 int rdns_len;
10244 char * agent;
10245 #endif /* CK_ANSIC */
10246 {
10247 char namecopy[NAMECPYL];
10248 char *p;
10249 int i, x, dns = 0;
10250 #ifdef TCPSOCKET
10251 int isconnect = 0;
10252 #ifdef SO_OOBINLINE
10253 int on = 1;
10254 #endif /* SO_OOBINLINE */
10255 struct servent *service=NULL;
10256 struct hostent *host=NULL;
10257 struct sockaddr_in r_addr;
10258 struct sockaddr_in sin;
10259 struct sockaddr_in l_addr;
10260 GSOCKNAME_T l_slen;
10261 #ifdef EXCELAN
10262 struct sockaddr_in send_socket;
10263 #endif /* EXCELAN */
10264
10265 #ifdef INADDRX
10266 /* inet_addr() is of type struct in_addr */
10267 #ifdef datageneral
10268 extern struct in_addr inet_addr();
10269 #else
10270 #ifdef HPUX5WINTCP
10271 extern struct in_addr inet_addr();
10272 #endif /* HPUX5WINTCP */
10273 #endif /* datageneral */
10274 struct in_addr iax;
10275 #else
10276 #ifdef INADDR_NONE
10277 struct in_addr iax;
10278 #else /* INADDR_NONE */
10279 long iax;
10280 #endif /* INADDR_NONE */
10281 #endif /* INADDRX */
10282
10283 if ( rdns_name == NULL || rdns_len < 0 )
10284 rdns_len = 0;
10285
10286 *http_ip = '\0'; /* Initialize IP address string */
10287 namecopy[0] = '\0';
10288
10289 #ifdef DEBUG
10290 if (deblog) {
10291 debug(F110,"http_open hostname",hostname,0);
10292 debug(F110,"http_open svcname",svcname,0);
10293 }
10294 #endif /* DEBUG */
10295 if (!hostname) hostname = "";
10296 if (!svcname) svcname = "";
10297 if (!*hostname || !*svcname) return(-1);
10298
10299
10300 service = ckgetservice(hostname,svcname,http_ip,20);
10301
10302 if (service == NULL) {
10303 if ( !quiet )
10304 printf("?Invalid service: %s\r\n",svcname);
10305 return(-1);
10306 }
10307
10308 /* For HTTP connections we must preserve the original hostname and */
10309 /* service requested so we can include them in the Host header. */
10310 ckmakmsg(http_host_port,sizeof(http_host_port),hostname,":",
10311 ckuitoa(ntohs(service->s_port)),NULL);
10312 http_port = ntohs(service->s_port);
10313 http_ssl = use_ssl;
10314 debug(F111,"http_open",http_host_port,http_port);
10315
10316 /* 'http_ip' contains the IP address to which we want to connect */
10317 /* 'svcnam' contains the service name */
10318 /* 'service->s_port' contains the port number in network byte order */
10319
10320 /* If we are using an http proxy, we need to create a buffer containing */
10321 /* hostname:port-number */
10322 /* to pass to the http_connect() function. Then we need to replace */
10323 /* 'namecopy' with the name of the proxy server and the service->s_port */
10324 /* with the port number of the proxy (default port 80). */
10325
10326 if ( tcp_http_proxy ) {
10327
10328 ckmakmsg(proxycopy,sizeof(proxycopy),hostname,":",
10329 ckuitoa(ntohs(service->s_port)),NULL);
10330 ckstrncpy(namecopy,tcp_http_proxy,NAMECPYL);
10331
10332 p = namecopy; /* Was a service requested? */
10333 while (*p != '\0' && *p != ':') p++; /* Look for colon */
10334 if (*p == ':') { /* Have a colon */
10335 debug(F110,"http_open name has colon",namecopy,0);
10336 *p++ = '\0'; /* Get service name or number */
10337 } else {
10338 strcpy(++p,"http");
10339 }
10340
10341 service = ckgetservice(namecopy,p,http_ip,20);
10342 if (!service) {
10343 fprintf(stderr, "Can't find port for service %s\n", p);
10344 #ifdef TGVORWIN
10345 debug(F101,"http_open can't get service for proxy","",socket_errno);
10346 #else
10347 debug(F101,"http_open can't get service for proxy","",errno);
10348 #endif /* TGVORWIN */
10349 errno = 0; /* (rather than mislead) */
10350 return(-1);
10351 }
10352
10353 /* copy the proxyname and remove the service if any so we can use
10354 * it as the hostname
10355 */
10356 ckstrncpy(namecopy,tcp_http_proxy,NAMECPYL);
10357 p = namecopy; /* Was a service requested? */
10358 while (*p != '\0' && *p != ':') p++; /* Look for colon */
10359 if (*p == ':') { /* Have a colon */
10360 *p = '\0'; /* terminate string */
10361 }
10362 hostname = namecopy; /* use proxy as hostname */
10363 }
10364
10365 /* Set up socket structure and get host address */
10366 bzero((char *)&r_addr, sizeof(r_addr));
10367 debug(F100,"http_open bzero ok","",0);
10368
10369 #ifdef INADDR_NONE
10370 debug(F101,"http_open INADDR_NONE defined","",INADDR_NONE);
10371 #else /* INADDR_NONE */
10372 debug(F100,"http_open INADDR_NONE not defined","",0);
10373 #endif /* INADDR_NONE */
10374 #ifdef INADDRX
10375 debug(F100,"http_open INADDRX defined","",0);
10376 #else /* INADDRX */
10377 debug(F100,"http_open INADDRX not defined","",0);
10378 #endif /* INADDRX */
10379
10380 #ifndef NOMHHOST
10381 #ifdef INADDRX
10382 iax = inet_addr(http_ip[0]?http_ip:hostname);
10383 debug(F111,"http_open inet_addr",http_ip[0]?http_ip:hostname,iax.s_addr);
10384 #else /* INADDRX */
10385 #ifdef INADDR_NONE
10386 iax.s_addr = inet_addr(http_ip[0]?http_ip:hostname);
10387 debug(F111,"http_open inet_addr",http_ip[0]?http_ip:hostname,iax.s_addr);
10388 #else /* INADDR_NONE */
10389 #ifndef datageneral
10390 iax = (unsigned int) inet_addr(http_ip[0]?http_ip:hostname);
10391 #else
10392 iax = -1L;
10393 #endif /* datageneral */
10394 debug(F111,"http_open inet_addr",http_ip[0]?http_ip:hostname,iax);
10395 #endif /* INADDR_NONE */
10396 #endif /* INADDRX */
10397
10398 dns = 0;
10399 if (
10400 #ifdef INADDR_NONE
10401 /* This might give warnings on 64-bit platforms but they should be harmless */
10402 /* because INADDR_NONE should be all 1's anyway, thus the OR part is */
10403 /* probably superfluous -- not sure why it's even there, maybe it should be */
10404 /* removed. */
10405 iax.s_addr == INADDR_NONE /* || iax.s_addr == (unsigned long) -1L */
10406 #else /* INADDR_NONE */
10407 iax == -1
10408 #endif /* INADDR_NONE */
10409 ) {
10410 if (!quiet) {
10411 printf(" DNS Lookup... ");
10412 fflush(stdout);
10413 }
10414 if ((host = gethostbyname(http_ip[0] ? http_ip : hostname)) != NULL) {
10415 debug(F100,"http_open gethostbyname != NULL","",0);
10416 host = ck_copyhostent(host);
10417 dns = 1; /* Remember we performed dns lookup */
10418 r_addr.sin_family = host->h_addrtype;
10419 if (tcp_rdns && host->h_name && host->h_name[0] && (rdns_len > 0)
10420 && (tcp_http_proxy == NULL)
10421 )
10422 ckmakmsg(rdns_name,rdns_len,host->h_name,":",svcname,NULL);
10423
10424 #ifdef HADDRLIST
10425 #ifdef h_addr
10426 /* This is for trying multiple IP addresses - see <netdb.h> */
10427 if (!(host->h_addr_list))
10428 return(-1);
10429 bcopy(host->h_addr_list[0],
10430 (caddr_t)&r_addr.sin_addr,
10431 host->h_length
10432 );
10433 #else
10434 bcopy(host->h_addr, (caddr_t)&r_addr.sin_addr, host->h_length);
10435 #endif /* h_addr */
10436 #else /* HADDRLIST */
10437 bcopy(host->h_addr, (caddr_t)&r_addr.sin_addr, host->h_length);
10438 #endif /* HADDRLIST */
10439 #ifdef COMMENT
10440 #ifndef EXCELAN
10441 debug(F111,"BCOPY","host->h_addr",host->h_addr);
10442 #endif /* EXCELAN */
10443 debug(F111,"BCOPY"," (caddr_t)&r_addr.sin_addr",
10444 (caddr_t)&r_addr.sin_addr);
10445 debug(F111,"BCOPY"," r_addr.sin_addr.s_addr",
10446 r_addr.sin_addr.s_addr);
10447 #endif /* COMMENT */
10448 debug(F111,"BCOPY","host->h_length",host->h_length);
10449 }
10450 }
10451 #endif /* NOMHHOST */
10452
10453 if (!dns) {
10454 #ifdef INADDRX
10455 /* inet_addr() is of type struct in_addr */
10456 struct in_addr ina;
10457 unsigned long uu;
10458 debug(F100,"http_open gethostbyname == NULL: INADDRX","",0);
10459 ina = inet_addr(http_ip[0]?http_ip:hostname);
10460 uu = *(unsigned int *)&ina;
10461 #else /* Not INADDRX */
10462 /* inet_addr() is unsigned long */
10463 unsigned long uu;
10464 debug(F100,"http_open gethostbyname == NULL: Not INADDRX","",0);
10465 uu = inet_addr(http_ip[0]?http_ip:hostname);
10466 #endif /* INADDRX */
10467 debug(F101,"http_open uu","",uu);
10468 if (
10469 #ifdef INADDR_NONE
10470 !(uu == INADDR_NONE || uu == (unsigned int) -1L)
10471 #else /* INADDR_NONE */
10472 uu != ((unsigned long)-1)
10473 #endif /* INADDR_NONE */
10474 ) {
10475 r_addr.sin_addr.s_addr = uu;
10476 r_addr.sin_family = AF_INET;
10477 } else {
10478 #ifdef VMS
10479 fprintf(stdout, "\r\n"); /* complete any previous message */
10480 #endif /* VMS */
10481 fprintf(stderr, "Can't get address for %s\n",
10482 http_ip[0]?http_ip:hostname);
10483 #ifdef TGVORWIN
10484 debug(F101,"http_open can't get address","",socket_errno);
10485 #else
10486 debug(F101,"http_open can't get address","",errno);
10487 #endif /* TGVORWIN */
10488 errno = 0; /* Rather than mislead */
10489 return(-1);
10490 }
10491 }
10492
10493 /* Get a file descriptor for the connection. */
10494
10495 r_addr.sin_port = service->s_port;
10496 ckstrncpy(http_ip,(char *)inet_ntoa(r_addr.sin_addr),20);
10497 debug(F110,"http_open trying",http_ip,0);
10498 if (!quiet && *http_ip) {
10499 printf(" Trying %s... ", http_ip);
10500 fflush(stdout);
10501 }
10502
10503 /* Loop to try additional IP addresses, if any. */
10504
10505 do {
10506 #ifdef EXCELAN
10507 send_socket.sin_family = AF_INET;
10508 send_socket.sin_addr.s_addr = 0;
10509 send_socket.sin_port = 0;
10510 if ((httpfd = socket(SOCK_STREAM, (struct sockproto *)0,
10511 &send_socket, SO_REUSEADDR)) < 0)
10512 #else /* EXCELAN */
10513 if ((httpfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
10514 #endif /* EXCELAN */
10515 {
10516 #ifdef EXCELAN
10517 experror("TCP socket error");
10518 #else
10519 #ifdef TGVORWIN
10520 #ifdef OLD_TWG
10521 errno = socket_errno;
10522 #endif /* OLD_TWG */
10523 socket_perror("TCP socket error");
10524 debug(F101,"http_open socket error","",socket_errno);
10525 #else
10526 perror("TCP socket error");
10527 debug(F101,"http_open socket error","",errno);
10528 #endif /* TGVORWIN */
10529 #endif /* EXCELAN */
10530 return (-1);
10531 }
10532 errno = 0;
10533
10534 /* If a specific TCP address on the local host is desired we */
10535 /* must bind it to the socket. */
10536 #ifndef datageneral
10537 if (tcp_address) {
10538 int s_errno;
10539
10540 debug(F110,"http_open binding socket to",tcp_address,0);
10541 bzero((char *)&sin,sizeof(sin));
10542 sin.sin_family = AF_INET;
10543 #ifdef INADDRX
10544 inaddrx = inet_addr(tcp_address);
10545 sin.sin_addr.s_addr = *(unsigned long *)&inaddrx;
10546 #else
10547 sin.sin_addr.s_addr = inet_addr(tcp_address);
10548 #endif /* INADDRX */
10549 sin.sin_port = 0;
10550 if (bind(httpfd, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
10551 s_errno = socket_errno; /* Save error code */
10552 #ifdef TCPIPLIB
10553 socket_close(httpfd);
10554 #else /* TCPIPLIB */
10555 close(httpfd);
10556 #endif /* TCPIPLIB */
10557 httpfd = -1;
10558 errno = s_errno; /* and report this error */
10559 debug(F101,"http_open bind errno","",errno);
10560 return(-1);
10561 }
10562 }
10563 #endif /* datageneral */
10564
10565 /* Now connect to the socket on the other end. */
10566
10567 #ifdef EXCELAN
10568 if (connect(httpfd, &r_addr) < 0)
10569 #else
10570 #ifdef NT
10571 WSASafeToCancel = 1;
10572 #endif /* NT */
10573 if (connect(httpfd, (struct sockaddr *)&r_addr, sizeof(r_addr)) < 0)
10574 #endif /* EXCELAN */
10575 {
10576 #ifdef NT
10577 WSASafeToCancel = 0;
10578 #endif /* NT */
10579 #ifdef OS2
10580 i = socket_errno;
10581 #else /* OS2 */
10582 #ifdef TGVORWIN
10583 i = socket_errno;
10584 #else
10585 i = errno; /* Save error code */
10586 #endif /* TGVORWIN */
10587 #endif /* OS2 */
10588 #ifdef HADDRLIST
10589 #ifdef h_addr
10590 if (host && host->h_addr_list && host->h_addr_list[1]) {
10591 perror("");
10592 host->h_addr_list++;
10593 bcopy(host->h_addr_list[0],
10594 (caddr_t)&r_addr.sin_addr,
10595 host->h_length);
10596
10597 ckstrncpy(http_ip,(char *)inet_ntoa(r_addr.sin_addr),20);
10598 debug(F110,"http_open h_addr_list",http_ip,0);
10599 if (!quiet && *http_ip) {
10600 printf(" Trying %s... ", http_ip);
10601 fflush(stdout);
10602 }
10603 #ifdef TCPIPLIB
10604 socket_close(httpfd); /* Close it. */
10605 #else
10606 close(httpfd);
10607 #endif /* TCPIPLIB */
10608 continue;
10609 }
10610 #endif /* h_addr */
10611 #endif /* HADDRLIST */
10612 http_close();
10613 httpfd = -1;
10614 errno = i; /* And report this error */
10615 #ifdef EXCELAN
10616 if (errno) experror("http_open connect");
10617 #else
10618 #ifdef TGVORWIN
10619 debug(F101,"http_open connect error","",socket_errno);
10620 /* if (errno) socket_perror("http_open connect"); */
10621 #ifdef OLD_TWG
10622 errno = socket_errno;
10623 #endif /* OLD_TWG */
10624 if (!quiet)
10625 socket_perror("http_open connect");
10626 #else /* TGVORWIN */
10627 debug(F101,"http_open connect errno","",errno);
10628 #ifdef VMS
10629 if (!quiet)
10630 perror("\r\nFailed");
10631 #else
10632 if (!quiet)
10633 perror("Failed");
10634 #endif /* VMS */
10635 #ifdef DEC_TCPIP
10636 if (!quiet)
10637 perror("http_open connect");
10638 #endif /* DEC_TCPIP */
10639 #ifdef CMU_TCPIP
10640 if (!quiet)
10641 perror("http_open connect");
10642 #endif /* CMU_TCPIP */
10643 #endif /* TGVORWIN */
10644 #endif /* EXCELAN */
10645 return(-1);
10646 }
10647 #ifdef NT
10648 WSASafeToCancel = 0;
10649 #endif /* NT */
10650 isconnect = 1;
10651 } while (!isconnect);
10652
10653 #ifdef NON_BLOCK_IO
10654 on = 1;
10655 x = socket_ioctl(httpfd,FIONBIO,&on);
10656 debug(F101,"http_open FIONBIO","",x);
10657 #endif /* NON_BLOCK_IO */
10658
10659 /* We have succeeded in connecting to the HTTP PROXY. So now we */
10660 /* need to attempt to connect through the proxy to the actual host */
10661 /* If that is successful, we have to pretend that we made a direct */
10662 /* connection to the actual host. */
10663
10664 if ( tcp_http_proxy ) {
10665 #ifdef OS2
10666 if (!agent)
10667 agent = "Kermit 95"; /* Default user agent */
10668 #else
10669 if (!agent)
10670 agent = "C-Kermit";
10671 #endif /* OS2 */
10672
10673 if (http_connect(httpfd,
10674 tcp_http_proxy_agent ? tcp_http_proxy_agent : agent,
10675 NULL,
10676 tcp_http_proxy_user,
10677 tcp_http_proxy_pwd,
10678 0,
10679 proxycopy
10680 ) < 0) {
10681 http_close();
10682 return(-1);
10683 }
10684 }
10685
10686 #ifdef SO_OOBINLINE
10687 /* See note on SO_OOBINLINE in netopen() */
10688 #ifdef datageneral
10689 setsockopt(httpfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
10690 #else
10691 #ifdef BSD43
10692 setsockopt(httpfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
10693 #else
10694 #ifdef OSF1
10695 setsockopt(httpfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
10696 #else
10697 #ifdef POSIX
10698 setsockopt(httpfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
10699 #else
10700 #ifdef MOTSV88R4
10701 setsockopt(httpfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
10702 #else
10703 #ifdef SOLARIS
10704 /*
10705 Maybe this applies to all SVR4 versions, but the other (else) way has been
10706 compiling and working fine on all the others, so best not to change it.
10707 */
10708 setsockopt(httpfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
10709 #else
10710 #ifdef OSK
10711 setsockopt(httpfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
10712 #else
10713 #ifdef OS2
10714 {
10715 int rc;
10716 rc = setsockopt(httpfd,
10717 SOL_SOCKET,
10718 SO_OOBINLINE,
10719 (char *) &on,
10720 sizeof on
10721 );
10722 debug(F111,"setsockopt SO_OOBINLINE",on ? "on" : "off" ,rc);
10723 }
10724 #else
10725 #ifdef VMS /* or, at least, VMS with gcc */
10726 setsockopt(httpfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
10727 #else
10728 #ifdef CLIX
10729 setsockopt(httpfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
10730 #else
10731 setsockopt(httpfd, SOL_SOCKET, SO_OOBINLINE, &on, sizeof on);
10732 #endif /* CLIX */
10733 #endif /* VMS */
10734 #endif /* OS2 */
10735 #endif /* OSK */
10736 #endif /* SOLARIS */
10737 #endif /* MOTSV88R4 */
10738 #endif /* POSIX */
10739 #endif /* BSD43 */
10740 #endif /* OSF1 */
10741 #endif /* datageneral */
10742 #endif /* SO_OOBINLINE */
10743
10744 #ifndef NOTCPOPTS
10745 #ifndef datageneral
10746 #ifdef SOL_SOCKET
10747 #ifdef TCP_NODELAY
10748 no_delay(ttyfd,tcp_nodelay);
10749 #endif /* TCP_NODELAY */
10750 #ifdef SO_KEEPALIVE
10751 keepalive(ttyfd,tcp_keepalive);
10752 #endif /* SO_KEEPALIVE */
10753 #ifdef SO_LINGER
10754 ck_linger(ttyfd,tcp_linger, tcp_linger_tmo);
10755 #endif /* SO_LINGER */
10756 #ifdef SO_SNDBUF
10757 sendbuf(ttyfd,tcp_sendbuf);
10758 #endif /* SO_SNDBUF */
10759 #ifdef SO_RCVBUF
10760 recvbuf(ttyfd,tcp_recvbuf);
10761 #endif /* SO_RCVBUF */
10762 #endif /* SOL_SOCKET */
10763 #endif /* datageneral */
10764 #endif /* NOTCPOPTS */
10765
10766 #ifndef datageneral
10767 /* Find out our own IP address. */
10768 /* We need the l_addr structure for [E]KLOGIN. */
10769 l_slen = sizeof(l_addr);
10770 bzero((char *)&l_addr, l_slen);
10771 #ifndef EXCELAN
10772 if (!getsockname(httpfd, (struct sockaddr *)&l_addr, &l_slen)) {
10773 char * s = (char *)inet_ntoa(l_addr.sin_addr);
10774 ckstrncpy(myipaddr, s, 20);
10775 debug(F110,"getsockname",myipaddr,0);
10776 }
10777 #endif /* EXCELAN */
10778 #endif /* datageneral */
10779
10780 /* See note in netopen() on Reverse DNS lookups */
10781 if (tcp_rdns == SET_ON) {
10782 #ifdef NT
10783 if (isWin95())
10784 sleep(1);
10785 #endif /* NT */
10786 if (!quiet) {
10787 printf(" Reverse DNS Lookup... ");
10788 fflush(stdout);
10789 }
10790 if (host = gethostbyaddr((char *)&r_addr.sin_addr,4,PF_INET)) {
10791 char * s;
10792 host = ck_copyhostent(host);
10793 debug(F100,"http_open gethostbyname != NULL","",0);
10794 if (!quiet) {
10795 printf("(OK)\n");
10796 fflush(stdout);
10797 }
10798 s = host->h_name;
10799 if (!s) { /* This can happen... */
10800 debug(F100,"http_open host->h_name is NULL","",0);
10801 s = "";
10802 }
10803 /* Something is wrong with inet_ntoa() on HPUX 10.xx */
10804 /* The compiler says "Integral value implicitly converted to */
10805 /* pointer in assignment." The prototype is right there */
10806 /* in <arpa/inet.h> so what's the problem? */
10807 /* Ditto in HP-UX 5.x, but not 8.x or 9.x... */
10808 if (!*s) { /* No name so substitute the address */
10809 debug(F100,"http_open host->h_name is empty","",0);
10810 s = inet_ntoa(r_addr.sin_addr); /* Convert address to string */
10811 if (!s) /* Trust No 1 */
10812 s = "";
10813 if (*s) { /* If it worked, use this string */
10814 ckstrncpy(http_ip,s,20);
10815 }
10816 s = http_ip; /* Otherwise stick with the IP */
10817 if (!*s) /* or failing that */
10818 s = http_host_port; /* the name we were called with. */
10819 }
10820 if (*s) /* return the rdns name */
10821 ckmakmsg(rdns_name,rdns_len,s,":",svcname,NULL);
10822
10823 if (!quiet && *s
10824 #ifndef NOICP
10825 && !doconx
10826 #endif /* NOICP */
10827 ) {
10828 printf(" %s connected on port %s\n",s,
10829 ckuitoa(ntohs(service->s_port)));
10830 #ifdef BETADEBUG
10831 /* This is simply for testing the DNS entries */
10832 if (host->h_aliases) {
10833 char ** a = host->h_aliases;
10834 while (*a) {
10835 printf(" alias => %s\n",*a);
10836 a++;
10837 }
10838 }
10839 #endif /* BETADEBUG */
10840 }
10841 } else {
10842 if (!quiet) printf("Failed.\n");
10843 }
10844 } else if (!quiet) printf("(OK)\n");
10845 if (!quiet) fflush(stdout);
10846
10847
10848 if ( tcp_http_proxy ) {
10849 /* Erase the IP address since we cannot reuse it */
10850 http_ip[0] = '\0';
10851 } else {
10852 /* This should already have been done but just in case */
10853 ckstrncpy(http_ip,(char *)inet_ntoa(r_addr.sin_addr),20);
10854 }
10855 makestr(&http_agent,agent);
10856
10857 #ifdef CK_SSL
10858 if (use_ssl && ck_ssleay_is_installed()) {
10859 if (!ssl_http_init(hostname)) {
10860 if (bio_err!=NULL) {
10861 BIO_printf(bio_err,"ssl_tn_init() failed\n");
10862 ERR_print_errors(bio_err);
10863 } else {
10864 fflush(stderr);
10865 fprintf(stderr,"ssl_tn_init() failed\n");
10866 ERR_print_errors_fp(stderr);
10867 }
10868 http_close();
10869 return(-1);
10870 } else if ( ck_ssl_http_client(httpfd,hostname) < 0 ) {
10871 http_close();
10872 return(-1);
10873 }
10874 }
10875 #endif /* CK_SSL */
10876 #endif /* TCPSOCKET */
10877
10878 return(0); /* Done. */
10879 }
10880
10881 int
10882 #ifdef CK_ANSIC
http_close(VOID)10883 http_close(VOID)
10884 #else /* CK_ANSIC */
10885 http_close()
10886 #endif /* CK_ANSIC */
10887 {
10888 int x = 0;
10889 debug(F101,"http_close","",httpfd);
10890
10891 #ifdef HTTP_BUFFERING
10892 http_count = 0;
10893 http_bufp = 0;
10894 #endif /* HTTP_BUFFERING */
10895
10896 if (httpfd == -1) /* Was open? */
10897 return(0); /* Wasn't. */
10898
10899 #ifndef OS2
10900 if (httpfd > -1) /* Was. */
10901 #endif /* OS2 */
10902 {
10903 #ifdef CK_SSL
10904 if (tls_http_active_flag) {
10905 if (ssl_debug_flag)
10906 BIO_printf(bio_err,"calling SSL_shutdown\n");
10907 SSL_shutdown(tls_http_con);
10908 tls_http_active_flag = 0;
10909 }
10910 #endif /* CK_SSL */
10911 #ifdef TCPIPLIB
10912 x = socket_close(httpfd); /* Close it. */
10913 #else
10914 #ifndef OS2
10915 x = close(httpfd);
10916 #endif /* OS2 */
10917 #endif /* TCPIPLIB */
10918 }
10919 httpfd = -1; /* Mark it as closed. */
10920 /* do not erase http_host_port, http_ip, http_port so they */
10921 /* can be used by http_reopen() */
10922 return(x);
10923 }
10924
10925
10926 /* http_tol()
10927 * Call with s = pointer to string, n = length.
10928 * Returns number of bytes actually written on success, or
10929 * -1 on i/o error, -2 if called improperly.
10930 */
10931
10932 int
http_tol(s,n)10933 http_tol(s,n) CHAR *s; int n; {
10934 int count = 0;
10935 int len = n;
10936 int try = 0;
10937
10938 if (httpfd == -1) {
10939 debug(F100,"http_tol socket is closed","",0);
10940 return -1;
10941 }
10942 debug(F101,"http_tol TCPIPLIB ttnet","",ttnet);
10943 #ifdef COMMENT
10944 ckhexdump("http_tol",s,n);
10945 #endif /* COMMENT */
10946
10947 #ifdef CK_SSL
10948 if (tls_http_active_flag) {
10949 int error, r;
10950 /* Write using SSL */
10951 ssl_retry:
10952 r = SSL_write(tls_http_con, s, len /* >1024?1024:len */);
10953 switch (SSL_get_error(tls_http_con,r)) {
10954 case SSL_ERROR_NONE:
10955 debug(F111,"http_tol","SSL_write",r);
10956 if ( r == len )
10957 return(n);
10958 s += r;
10959 len -= r;
10960 goto ssl_retry;
10961 case SSL_ERROR_WANT_WRITE:
10962 debug(F100,"http_tol SSL_ERROR_WANT_WRITE","",0);
10963 return(-1);
10964 case SSL_ERROR_WANT_READ:
10965 debug(F100,"http_tol SSL_ERROR_WANT_READ","",0);
10966 return(-1);
10967 case SSL_ERROR_SYSCALL:
10968 if ( r == 0 ) { /* EOF */
10969 http_close();
10970 return(-2);
10971 } else {
10972 int rc = -1;
10973 #ifdef NT
10974 int gle = GetLastError();
10975 debug(F111,"http_tol SSL_ERROR_SYSCALL",
10976 "GetLastError()",gle);
10977 rc = os2socketerror(gle);
10978 if (rc == -1)
10979 rc = -2;
10980 else if ( rc == -2 )
10981 return -1;
10982 #endif /* NT */
10983 return(rc);
10984 }
10985 case SSL_ERROR_WANT_X509_LOOKUP:
10986 debug(F100,"http_tol SSL_ERROR_WANT_X509_LOOKUP","",0);
10987 http_close();
10988 return(-2);
10989 case SSL_ERROR_SSL:
10990 debug(F100,"http_tol SSL_ERROR_SSL","",0);
10991 http_close();
10992 return(-2);
10993 case SSL_ERROR_ZERO_RETURN:
10994 debug(F100,"http_tol SSL_ERROR_ZERO_RETURN","",0);
10995 http_close();
10996 return(-2);
10997 default:
10998 debug(F100,"http_tol SSL_ERROR_?????","",0);
10999 http_close();
11000 return(-2);
11001 }
11002 }
11003 #endif /* CK_SSL */
11004
11005 http_tol_retry:
11006 try++; /* Increase the try counter */
11007
11008 {
11009 #ifdef BSDSELECT
11010 fd_set wfds;
11011 struct timeval tv;
11012
11013 debug(F101,"http_tol BSDSELECT","",0);
11014 tv.tv_usec = 0L;
11015 tv.tv_sec=30;
11016 #ifdef NT
11017 WSASafeToCancel = 1;
11018 #endif /* NT */
11019 #ifdef STREAMING
11020 do_select:
11021 #endif /* STREAMING */
11022 FD_ZERO(&wfds);
11023 FD_SET(httpfd, &wfds);
11024 if (select(FD_SETSIZE, NULL,
11025 #ifdef __DECC
11026 #ifndef __DECC_VER
11027 (int *)
11028 #endif /* __DECC_VER */
11029 #endif /* __DECC */
11030 &wfds, NULL, &tv) < 0) {
11031 int s_errno = socket_errno;
11032 debug(F101,"http_tol select failed","",s_errno);
11033 #ifdef BETADEBUG
11034 printf("http_tol select failed: %d\n", s_errno);
11035 #endif /* BETADEBUG */
11036 #ifdef NT
11037 WSASafeToCancel = 0;
11038 if (!win95selectbug)
11039 #endif /* NT */
11040 return(-1);
11041 }
11042 if (!FD_ISSET(httpfd, &wfds)) {
11043 #ifdef STREAMING
11044 if (streaming)
11045 goto do_select;
11046 #endif /* STREAMING */
11047 debug(F111,"http_tol","!FD_ISSET",ttyfd);
11048 #ifdef NT
11049 WSASafeToCancel = 0;
11050 if (!win95selectbug)
11051 #endif /* NT */
11052 return(-1);
11053 }
11054 #ifdef NT
11055 WSASafeToCancel = 0;
11056 #endif /* NT */
11057 #else /* BSDSELECT */
11058 #ifdef IBMSELECT
11059 {
11060 int tries = 0;
11061 debug(F101,"http_tol IBMSELECT","",0);
11062 while (select(&httpfd, 0, 1, 0, 1000) != 1) {
11063 int count;
11064 if (tries++ >= 60) {
11065 /* if after 60 seconds we can't get permission to write */
11066 debug(F101,"http_tol select failed","",socket_errno);
11067 return(-1);
11068 }
11069 #ifdef COMMENT
11070 if ((count = http_tchk()) < 0) {
11071 debug(F111,"http_tol","http_tchk()",count);
11072 return(count);
11073 }
11074 #endif /* COMMENT */
11075 }
11076 }
11077 #endif /* IBMSELECT */
11078 #endif /* BSDSELECT */
11079 #ifdef TCPIPLIB
11080 if ((count = socket_write(httpfd,s,n)) < 0) {
11081 int s_errno = socket_errno; /* maybe a function */
11082 debug(F101,"http_tol socket_write error","",s_errno);
11083 #ifdef OS2
11084 if (os2socketerror(s_errno) < 0)
11085 return(-2);
11086 #endif /* OS2 */
11087 return(-1); /* Call it an i/o error */
11088 }
11089 #else /* TCPIPLIB */
11090 if ((count = write(httpfd,s,n)) < 0) {
11091 debug(F101,"http_tol socket_write error","",errno);
11092 return(-1); /* Call it an i/o error */
11093 }
11094 #endif /* TCPIPLIB */
11095 if (count < n) {
11096 debug(F111,"http_tol socket_write",s,count);
11097 if (try > 25) {
11098 /* don't try more than 25 times */
11099 debug(F100,"http_tol tried more than 25 times","",0);
11100 return(-1);
11101 }
11102 if (count > 0) {
11103 s += count;
11104 n -= count;
11105 }
11106 debug(F111,"http_tol retry",s,n);
11107 goto http_tol_retry;
11108 } else {
11109 debug(F111,"http_tol socket_write",s,count);
11110 return(len); /* success - return total length */
11111 }
11112 }
11113 }
11114
11115 int
http_inc(timo)11116 http_inc(timo) int timo; {
11117 int x=-1; unsigned char c; /* The locals. */
11118
11119 if (httpfd == -1) {
11120 #ifdef HTTP_BUFFERING
11121 http_count = 0;
11122 http_bufp = 0;
11123 #endif /* HTTP_BUFFERING */
11124 debug(F100,"http_inc socket is closed","",0);
11125 return(-2);
11126 }
11127
11128 #ifdef CK_SSL
11129 /*
11130 * In the case of OpenSSL, it is possible that there is still
11131 * data waiting in the SSL session buffers that has not yet
11132 * been read by Kermit. If this is the case we must process
11133 * it without calling select() because select() will not return
11134 * with an indication that there is data to be read from the
11135 * socket. If there is no data pending in the SSL session
11136 * buffers then fall through to the select() code and wait for
11137 * some data to arrive.
11138 */
11139 if (tls_http_active_flag) {
11140 int error;
11141
11142 x = SSL_pending(tls_http_con);
11143 if (x < 0) {
11144 debug(F111,"http_inc","SSL_pending error",x);
11145 http_close();
11146 return(-1);
11147 } else if ( x > 0 ) {
11148 ssl_read:
11149 x = SSL_read(tls_http_con, &c, 1);
11150 error = SSL_get_error(tls_http_con,x);
11151 switch (error) {
11152 case SSL_ERROR_NONE:
11153 debug(F111,"http_inc SSL_ERROR_NONE","x",x);
11154 if (x > 0) {
11155 #ifdef OS2
11156 ReleaseTCPIPMutex();
11157 #endif /* OS2 */
11158 return(c); /* Return character. */
11159 } else if (x < 0) {
11160 #ifdef OS2
11161 ReleaseTCPIPMutex();
11162 #endif /* OS2 */
11163 return(-1);
11164 } else {
11165 http_close();
11166 #ifdef OS2
11167 ReleaseTCPIPMutex();
11168 #endif /* OS2 */
11169 return(-2);
11170 }
11171 case SSL_ERROR_WANT_WRITE:
11172 debug(F100,"http_inc SSL_ERROR_WANT_WRITE","",0);
11173 #ifdef OS2
11174 ReleaseTCPIPMutex();
11175 #endif /* OS2 */
11176 return(-1);
11177 case SSL_ERROR_WANT_READ:
11178 debug(F100,"http_inc SSL_ERROR_WANT_READ","",0);
11179 #ifdef OS2
11180 ReleaseTCPIPMutex();
11181 #endif /* OS2 */
11182 return(-1);
11183 case SSL_ERROR_SYSCALL:
11184 if ( x == 0 ) { /* EOF */
11185 http_close();
11186 #ifdef OS2
11187 ReleaseTCPIPMutex();
11188 #endif /* OS2 */
11189 return(-2);
11190 } else {
11191 int rc = -1;
11192 #ifdef NT
11193 int gle = GetLastError();
11194 debug(F111,"http_inc SSL_ERROR_SYSCALL",
11195 "GetLastError()",gle);
11196 rc = os2socketerror(gle);
11197 if (rc == -1)
11198 rc = -2;
11199 else if ( rc == -2 )
11200 rc = -1;
11201 #endif /* NT */
11202 #ifdef OS2
11203 ReleaseTCPIPMutex();
11204 #endif /* OS2 */
11205 return(rc);
11206 }
11207 case SSL_ERROR_WANT_X509_LOOKUP:
11208 debug(F100,"http_inc SSL_ERROR_WANT_X509_LOOKUP","",0);
11209 http_close();
11210 #ifdef OS2
11211 ReleaseTCPIPMutex();
11212 #endif /* OS2 */
11213 return(-2);
11214 case SSL_ERROR_SSL:
11215 debug(F100,"http_inc SSL_ERROR_SSL","",0);
11216 #ifdef COMMENT
11217 http_close();
11218 #endif /* COMMENT */
11219 #ifdef OS2
11220 ReleaseTCPIPMutex();
11221 #endif /* OS2 */
11222 return(-2);
11223 case SSL_ERROR_ZERO_RETURN:
11224 debug(F100,"http_inc SSL_ERROR_ZERO_RETURN","",0);
11225 http_close();
11226 #ifdef OS2
11227 ReleaseTCPIPMutex();
11228 #endif /* OS2 */
11229 return(-2);
11230 default:
11231 debug(F100,"http_inc SSL_ERROR_?????","",0);
11232 http_close();
11233 #ifdef OS2
11234 ReleaseTCPIPMutex();
11235 #endif /* OS2 */
11236 return(-2);
11237 }
11238 }
11239 }
11240 #endif /* CK_SSL */
11241
11242 #ifdef HTTP_BUFFERING
11243 /* Skip all the select() stuff if we have bytes buffered locally */
11244 if (http_count > 0)
11245 goto getfrombuffer;
11246 #endif /* HTTP_BUFFERING */
11247
11248 {
11249 #ifdef BSDSELECT
11250 fd_set rfds;
11251 struct timeval tv;
11252 int timeout = timo < 0 ? -timo : 1000 * timo;
11253 debug(F101,"http_inc BSDSELECT","",timo);
11254
11255 for ( ; timeout >= 0; timeout -= (timo ? 100 : 0)) {
11256 int rc;
11257 debug(F111,"http_inc","timeout",timeout);
11258 /* Don't move select() initialization out of the loop. */
11259 FD_ZERO(&rfds);
11260 FD_SET(httpfd, &rfds);
11261 tv.tv_sec = tv.tv_usec = 0L;
11262 if (timo)
11263 tv.tv_usec = (long) 100000L;
11264 else
11265 tv.tv_sec = 30;
11266 #ifdef NT
11267 WSASafeToCancel = 1;
11268 #endif /* NT */
11269 rc = select(FD_SETSIZE,
11270 #ifndef __DECC
11271 (fd_set *)
11272 #endif /* __DECC */
11273 &rfds, NULL, NULL, &tv);
11274 if (rc < 0) {
11275 int s_errno = socket_errno;
11276 debug(F111,"http_inc","select",rc);
11277 debug(F111,"http_inc","socket_errno",s_errno);
11278 #ifdef HTTP_BUFFERING
11279 http_count = 0;
11280 http_bufp = 0;
11281 #endif /* HTTP_BUFFERING */
11282 if (s_errno)
11283 return(-1);
11284 }
11285 debug(F111,"http_inc","select",rc);
11286 #ifdef NT
11287 WSASafeToCancel = 0;
11288 #endif /* NT */
11289 if (FD_ISSET(httpfd, &rfds)) {
11290 x = 0;
11291 break;
11292 } else {
11293 /* If waiting forever we have no way of knowing if the */
11294 /* socket closed so try writing a 0-length TCP packet */
11295 /* which should force an error if the socket is closed */
11296 if (!timo) {
11297 #ifdef TCPIPLIB
11298 if ((rc = socket_write(httpfd,"",0)) < 0) {
11299 #ifdef HTTP_BUFFERING
11300 http_count = 0;
11301 http_bufp = 0;
11302 #endif /* HTTP_BUFFERING */
11303 int s_errno = socket_errno;
11304 debug(F101,"http_inc socket_write error","",s_errno);
11305 #ifdef OS2
11306 if (os2socketerror(s_errno) < 0)
11307 return(-2);
11308 #endif /* OS2 */
11309 return(-1); /* Call it an i/o error */
11310 }
11311 #else /* TCPIPLIB */
11312 if ((rc = write(httpfd,"",0)) < 0) {
11313 #ifdef HTTP_BUFFERING
11314 http_count = 0;
11315 http_bufp = 0;
11316 #endif /* HTTP_BUFFERING */
11317 debug(F101,"http_inc socket_write error","",errno);
11318 return(-1); /* Call it an i/o error */
11319 }
11320 #endif /* TCPIPLIB */
11321 }
11322 continue;
11323 }
11324 }
11325 #ifdef NT
11326 WSASafeToCancel = 0;
11327 #endif /* NT */
11328 #else /* !BSDSELECT */
11329 #ifdef IBMSELECT
11330 /*
11331 Was used by OS/2, currently not used, but might come in handy some day...
11332 ... and it came in handy! For our TCP/IP layer, it avoids all the fd_set
11333 and timeval stuff since this is the only place where it is used.
11334 */
11335 int socket = httpfd;
11336 int timeout = timo < 0 ? -timo : 1000 * timo;
11337
11338 debug(F101,"http_inc IBMSELECT","",timo);
11339 for ( ; timeout >= 0; timeout -= (timo ? 100 : 0)) {
11340 if (select(&socket, 1, 0, 0, 100L) == 1) {
11341 x = 0;
11342 break;
11343 }
11344 }
11345 #else /* !IBMSELECT */
11346 SELECT is required for this code
11347 #endif /* IBMSELECT */
11348 #endif /* BSDSELECT */
11349 }
11350
11351 if (timo && x < 0) { /* select() timed out */
11352 #ifdef HTTP_BUFFERING
11353 http_count = 0;
11354 http_bufp = 0;
11355 #endif /* HTTP_BUFFERING */
11356 debug(F100,"http_inc select() timed out","",0);
11357 return(-1); /* Call it an i/o error */
11358 }
11359
11360 #ifdef CK_SSL
11361 if ( tls_http_active_flag ) {
11362 int error;
11363 ssl_read2:
11364 x = SSL_read(tls_http_con, &c, 1);
11365 error = SSL_get_error(tls_http_con,x);
11366 switch (error) {
11367 case SSL_ERROR_NONE:
11368 debug(F111,"http_inc SSL_ERROR_NONE","x",x);
11369 if (x > 0) {
11370 #ifdef OS2
11371 ReleaseTCPIPMutex();
11372 #endif /* OS2 */
11373 return(c); /* Return character. */
11374 } else if (x < 0) {
11375 #ifdef OS2
11376 ReleaseTCPIPMutex();
11377 #endif /* OS2 */
11378 return(-1);
11379 } else {
11380 http_close();
11381 #ifdef OS2
11382 ReleaseTCPIPMutex();
11383 #endif /* OS2 */
11384 return(-2);
11385 }
11386 case SSL_ERROR_WANT_WRITE:
11387 debug(F100,"http_inc SSL_ERROR_WANT_WRITE","",0);
11388 #ifdef OS2
11389 ReleaseTCPIPMutex();
11390 #endif /* OS2 */
11391 return(-1);
11392 case SSL_ERROR_WANT_READ:
11393 debug(F100,"http_inc SSL_ERROR_WANT_READ","",0);
11394 #ifdef OS2
11395 ReleaseTCPIPMutex();
11396 #endif /* OS2 */
11397 return(-1);
11398 case SSL_ERROR_SYSCALL:
11399 if ( x == 0 ) { /* EOF */
11400 http_close();
11401 #ifdef OS2
11402 ReleaseTCPIPMutex();
11403 #endif /* OS2 */
11404 return(-2);
11405 } else {
11406 int rc = -1;
11407 #ifdef NT
11408 int gle = GetLastError();
11409 debug(F111,"http_inc SSL_ERROR_SYSCALL",
11410 "GetLastError()",gle);
11411 rc = os2socketerror(gle);
11412 if (rc == -1)
11413 rc = -2;
11414 else if ( rc == -2 )
11415 rc = -1;
11416 #endif /* NT */
11417 #ifdef OS2
11418 ReleaseTCPIPMutex();
11419 #endif /* OS2 */
11420 return(rc);
11421 }
11422 case SSL_ERROR_WANT_X509_LOOKUP:
11423 debug(F100,"http_inc SSL_ERROR_WANT_X509_LOOKUP","",0);
11424 http_close();
11425 #ifdef OS2
11426 ReleaseTCPIPMutex();
11427 #endif /* OS2 */
11428 return(-2);
11429 case SSL_ERROR_SSL:
11430 debug(F100,"http_inc SSL_ERROR_SSL","",0);
11431 #ifdef COMMENT
11432 http_close();
11433 #endif /* COMMENT */
11434 #ifdef OS2
11435 ReleaseTCPIPMutex();
11436 #endif /* OS2 */
11437 return(-2);
11438 case SSL_ERROR_ZERO_RETURN:
11439 debug(F100,"http_inc SSL_ERROR_ZERO_RETURN","",0);
11440 http_close();
11441 #ifdef OS2
11442 ReleaseTCPIPMutex();
11443 #endif /* OS2 */
11444 return(-2);
11445 default:
11446 debug(F100,"http_inc SSL_ERROR_?????","",0);
11447 http_close();
11448 #ifdef OS2
11449 ReleaseTCPIPMutex();
11450 #endif /* OS2 */
11451 return(-2);
11452 }
11453 }
11454 #endif /* CK_SSL */
11455
11456 #ifdef HTTP_BUFFERING
11457 /*
11458 Buffering code added by fdc 15 Dec 2005 for non-SSL case only because HTTP
11459 GETs were orders of magnitude too slow due to the single-byte read()s. The
11460 file-descriptor swapping is pretty gross, but the more elegant solution
11461 (calling a nettchk() like routine with the fd as a parameter) doesn't work,
11462 because nettchk() relies on too many other routines that, like itself, are
11463 hardwired for ttyfd.
11464 */
11465 getfrombuffer:
11466 if (--http_count >= 0) {
11467 c = http_inbuf[http_bufp++];
11468 x = 1;
11469 } else {
11470 int savefd;
11471 savefd = ttyfd;
11472 ttyfd = httpfd;
11473 x = nettchk();
11474 ttyfd = savefd;
11475 debug(F101,"http_inc nettchk","",x);
11476 if (x > HTTP_INBUFLEN)
11477 x = HTTP_INBUFLEN;
11478 #ifdef TCPIPLIB
11479 x = socket_read(httpfd,http_inbuf,x);
11480 #else /* Not TCPIPLIB */
11481 x = read(httpfd,http_inbuf,x);
11482 #endif /* TCPIPLIB */
11483 http_count = 0;
11484 http_bufp = 0;
11485 if (x > 0) {
11486 c = http_inbuf[http_bufp++];
11487 http_count = x - 1;
11488 }
11489 }
11490 #else /* Not HTTP_BUFFERING */
11491 #ifdef TCPIPLIB
11492 x = socket_read(httpfd,&c,1);
11493 #else /* Not TCPIPLIB */
11494 x = read(httpfd,&c,1);
11495 #endif /* TCPIPLIB */
11496 #endif /* HTTP_BUFFERING */
11497
11498 if (x <= 0) {
11499 int s_errno = socket_errno;
11500 debug(F101,"ttbufr socket_read","",x);
11501 debug(F101,"ttbufr socket_errno","",s_errno);
11502 #ifdef OS2
11503 if (x == 0 || os2socketerror(s_errno) < 0) {
11504 http_close();
11505 ReleaseTCPIPMutex();
11506 return(-2);
11507 }
11508 ReleaseTCPIPMutex();
11509 return(-1);
11510 #else /* OS2 */
11511 http_close(); /* *** *** */
11512 return(-2);
11513 #endif /* OS2 */
11514 }
11515 return(c);
11516 }
11517
11518 void
11519 #ifdef CK_ANSIC
http_set_code_reply(char * msg)11520 http_set_code_reply(char * msg)
11521 #else
11522 http_set_code_reply(msg)
11523 char * msg;
11524 #endif /* CK_ANSIC */
11525 {
11526 char * p = msg;
11527 char buf[16];
11528 int i=0;
11529
11530 while ( *p != SP && *p != NUL ) {
11531 buf[i] = *p;
11532 p++;
11533 i++;
11534 }
11535
11536 http_code = atoi(buf);
11537
11538 while ( *p == SP )
11539 p++;
11540
11541 ckstrncpy(http_reply_str,p,HTTPBUFLEN);
11542 }
11543
11544 int
11545 #ifdef CK_ANSIC
http_get(char * agent,char ** hdrlist,char * user,char * pwd,char array,char * local,char * remote,int stdio)11546 http_get(char * agent, char ** hdrlist, char * user,
11547 char * pwd, char array, char * local, char * remote,
11548 int stdio)
11549 #else
11550 http_get(agent, hdrlist, user, pwd, array, local, remote, stdio)
11551 char * agent; char ** hdrlist; char * user;
11552 char * pwd; char array; char * local; char * remote;
11553 int stdio;
11554 #endif /* CK_ANSIC */
11555 {
11556 char * request = NULL;
11557 int i, j, len = 0, hdcnt = 0, rc = 0;
11558 int ch;
11559 int http_fnd = 0;
11560 char buf[HTTPBUFLEN], *p;
11561 int nullline;
11562 #ifdef OS2
11563 struct utimbuf u_t;
11564 #else /* OS2 */
11565 #ifdef SYSUTIMEH
11566 struct utimbuf u_t;
11567 #else
11568 struct utimbuf {
11569 time_t atime;
11570 time_t mtime;
11571 } u_t;
11572 #endif /* SYSUTIMH */
11573 #endif /* OS2 */
11574 time_t mod_t = 0;
11575 time_t srv_t = 0;
11576 time_t local_t = 0;
11577 char passwd[64];
11578 char b64in[128];
11579 char b64out[256];
11580 char * headers[HTTPHEADCNT];
11581 int closecon = 0;
11582 int chunked = 0;
11583 int zfile = 0;
11584 int first = 1;
11585
11586 #ifdef DEBUG
11587 if (deblog) {
11588 debug(F101,"http_get httpfd","",httpfd);
11589 debug(F110,"http_agent",agent,0);
11590 debug(F110,"http_user",user,0);
11591 debug(F110,"http_local",local,0);
11592 debug(F110,"http_remote",remote,0);
11593 }
11594 #endif /* DEBUG */
11595 if (!remote) remote = "";
11596
11597 if (httpfd == -1)
11598 return(-1);
11599
11600 if (array) {
11601 for (i = 0; i < HTTPHEADCNT; i++)
11602 headers[i] = NULL;
11603 }
11604 len = 8; /* GET */
11605 len += strlen(HTTP_VERSION);
11606 len += strlen(remote);
11607 len += 16;
11608
11609 if (hdrlist) {
11610 for (i = 0; hdrlist[i]; i++)
11611 len += strlen(hdrlist[i]) + 2;
11612 }
11613 len += (int) strlen(http_host_port) + 8;
11614
11615 if (agent)
11616 len += 13 + strlen(agent);
11617 if (user) {
11618 if (!pwd) {
11619 readpass("Password: ",passwd,64);
11620 pwd = passwd;
11621 }
11622 ckmakmsg(b64in,sizeof(b64in),user,":",pwd,NULL);
11623 j = b8tob64(b64in,strlen(b64in),b64out,256);
11624 memset(pwd,0,strlen(pwd)); /* NOT PORTABLE */
11625 if (j < 0)
11626 return(-1);
11627 b64out[j] = '\0';
11628 len += j + 24;
11629 }
11630 #ifdef HTTP_CLOSE
11631 len += 19; /* Connection: close */
11632 #endif
11633 len += 3; /* blank line + null */
11634
11635 request = malloc(len);
11636 if (!request)
11637 return(-1);
11638
11639 sprintf(request,"GET %s %s\r\n",remote,HTTP_VERSION); /* safe */
11640 ckstrncat(request,"Host: ", len);
11641 ckstrncat(request,http_host_port, len);
11642 ckstrncat(request,"\r\n",len);
11643 if (agent) {
11644 ckstrncat(request,"User-agent: ",len);
11645 ckstrncat(request,agent,len);
11646 ckstrncat(request,"\r\n",len);
11647 }
11648 if (user) {
11649 ckstrncat(request,"Authorization: Basic ",len);
11650 ckstrncat(request,b64out,len);
11651 ckstrncat(request,"\r\n",len);
11652 }
11653 if ( hdrlist ) {
11654 for (i = 0; hdrlist[i]; i++) {
11655 ckstrncat(request,hdrlist[i],len);
11656 ckstrncat(request,"\r\n",len);
11657 }
11658 }
11659 #ifdef HTTP_CLOSE
11660 ckstrncat(request,"Connection: close\r\n",len);
11661 #endif
11662 ckstrncat(request,"\r\n",len);
11663
11664 getreq:
11665 if (http_tol((CHAR *)request,strlen(request)) < 0)
11666 {
11667 http_close();
11668 if ( first ) {
11669 first--;
11670 http_reopen();
11671 goto getreq;
11672 }
11673 rc = -1;
11674 goto getexit;
11675 }
11676
11677 /* Process the headers */
11678 local_t = time(NULL);
11679 nullline = 0;
11680 i = 0;
11681 len = -1;
11682 while (!nullline && (ch = http_inc(0)) >= 0 && i < HTTPBUFLEN) {
11683 buf[i] = ch;
11684 if ( buf[i] == 10 ) { /* found end of line */
11685 if (i > 0 && buf[i-1] == 13)
11686 i--;
11687 if (i < 1)
11688 nullline = 1;
11689 buf[i] = '\0';
11690 if (array && !nullline && hdcnt < HTTPHEADCNT)
11691 makestr(&headers[hdcnt++],buf);
11692 if (!ckstrcmp(buf,"HTTP",4,0)) {
11693 http_fnd = 1;
11694 j = ckindex(" ",buf,0,0,0);
11695 p = &buf[j];
11696 while ( isspace(*p) )
11697 p++;
11698 switch ( p[0] ) {
11699 case '1': /* Informational message */
11700 break;
11701 case '2': /* Success */
11702 break;
11703 case '3': /* Redirection */
11704 case '4': /* Client failure */
11705 case '5': /* Server failure */
11706 default: /* Unknown */
11707 if (!quiet)
11708 printf("Failure: Server reports %s\n",p);
11709 rc = -1;
11710 local = NULL;
11711 }
11712 http_set_code_reply(p);
11713 #ifdef CMDATE2TM
11714 } else if (!ckstrcmp(buf,"Last-Modified",13,0)) {
11715 mod_t = http_date(&buf[15]);
11716 } else if (!ckstrcmp(buf,"Date",4,0)) {
11717 srv_t = http_date(&buf[4]);
11718 #endif /* CMDATE2TM */
11719 } else if (!ckstrcmp(buf,"Connection:",11,0)) {
11720 if ( ckindex("close",buf,11,0,0) != 0 )
11721 closecon = 1;
11722 } else if (!ckstrcmp(buf,"Content-Length:",15,0)) {
11723 len = atoi(&buf[16]);
11724 } else if (!ckstrcmp(buf,"Transfer-Encoding:",18,0)) {
11725 if ( ckindex("chunked",buf,18,0,0) != 0 )
11726 chunked = 1;
11727 debug(F101,"http_get chunked","",chunked);
11728 }
11729 i = 0;
11730 } else {
11731 i++;
11732 }
11733 }
11734 if (ch < 0 && first) {
11735 first--;
11736 http_close();
11737 http_reopen();
11738 goto getreq;
11739 }
11740 if (http_fnd == 0) {
11741 rc = -1;
11742 closecon = 1;
11743 goto getexit;
11744 }
11745
11746 /* Now we have the contents of the file */
11747 if ( local && local[0] ) {
11748 if (zopeno(ZOFILE,local,NULL,NULL))
11749 zfile = 1;
11750 else
11751 rc = -1;
11752 }
11753
11754 if ( chunked ) {
11755 while ((len = http_get_chunk_len()) > 0) {
11756 while (len && (ch = http_inc(0)) >= 0) {
11757 len--;
11758 if ( zfile )
11759 zchout(ZOFILE,(CHAR)ch);
11760 if ( stdio )
11761 conoc((CHAR)ch);
11762 }
11763 if ((ch = http_inc(0)) != CR)
11764 break;
11765 if ((ch = http_inc(0)) != LF)
11766 break;
11767 }
11768 } else {
11769 while (len && (ch = http_inc(0)) >= 0) {
11770 len--;
11771 if ( zfile )
11772 zchout(ZOFILE,(CHAR)ch);
11773 if ( stdio )
11774 conoc((CHAR)ch);
11775 }
11776 }
11777
11778 if ( zfile )
11779 zclose(ZOFILE);
11780
11781 if ( chunked ) { /* Parse Trailing Headers */
11782 nullline = 0;
11783 while (!nullline && (ch = http_inc(0)) >= 0 && i < HTTPBUFLEN) {
11784 buf[i] = ch;
11785 if ( buf[i] == 10 ) { /* found end of line */
11786 if (i > 0 && buf[i-1] == 13)
11787 i--;
11788 if (i < 1)
11789 nullline = 1;
11790 buf[i] = '\0';
11791 if (array && !nullline && hdcnt < HTTPHEADCNT)
11792 makestr(&headers[hdcnt++],buf);
11793 #ifdef CMDATE2TM
11794 if (!ckstrcmp(buf,"Last-Modified",13,0)) {
11795 mod_t = http_date(&buf[15]);
11796 } else if (!ckstrcmp(buf,"Date",4,0)) {
11797 srv_t = http_date(&buf[4]);
11798 }
11799 #endif /* CMDATE2TM */
11800 else if (!ckstrcmp(buf,"Connection:",11,0)) {
11801 if ( ckindex("close",buf,11,0,0) != 0 )
11802 closecon = 1;
11803 }
11804 i = 0;
11805 } else {
11806 i++;
11807 }
11808 }
11809 }
11810
11811 if ( zfile ) { /* Set timestamp */
11812 #ifndef NOSETTIME
11813 #ifdef OS2
11814 u_t.actime = srv_t ? srv_t : local_t;
11815 u_t.modtime = mod_t ? mod_t : local_t;
11816 #else /* OS2 */
11817 #ifdef SYSUTIMEH
11818 u_t.actime = srv_t ? srv_t : local_t;
11819 u_t.modtime = mod_t ? mod_t : local_t;
11820 #else
11821 #ifdef BSD44
11822 u_t[0].tv_sec = srv_t ? srv_t : local_t;
11823 u_t[1].tv_sec = mod_t ? mod_t : local_t;
11824 #else
11825 u_t.mtime = srv_t ? srv_t : local_t;
11826 u_t.atime = mod_t ? mod_t : local_t;
11827 #endif /* BSD44 */
11828 #endif /* SYSUTIMEH */
11829 #endif /* OS2 */
11830 utime(local,&u_t);
11831 #endif /* NOSETTIME */
11832 }
11833
11834 getexit:
11835 if (array)
11836 http_mkarray(headers,hdcnt,array);
11837
11838 if ( closecon )
11839 http_close();
11840 free(request);
11841 for (i = 0; i < hdcnt; i++) {
11842 if (headers[i])
11843 free(headers[i]);
11844 }
11845 return(rc);
11846 }
11847
11848 int
11849 #ifdef CK_ANSIC
http_head(char * agent,char ** hdrlist,char * user,char * pwd,char array,char * local,char * remote,int stdio)11850 http_head(char * agent, char ** hdrlist, char * user,
11851 char * pwd, char array, char * local, char * remote,
11852 int stdio)
11853 #else
11854 http_head(agent, hdrlist, user, pwd, array, local, remote, stdio)
11855 char * agent; char ** hdrlist; char * user;
11856 char * pwd; char array; char * local; char * remote;
11857 int stdio;
11858 #endif /* CK_ANSIC */
11859 {
11860 char * request = NULL;
11861 int i, j, len = 0, hdcnt = 0, rc = 0;
11862 int ch;
11863 int http_fnd = 0;
11864 char buf[HTTPBUFLEN], *p;
11865 int nullline;
11866 time_t mod_t;
11867 time_t srv_t;
11868 time_t local_t;
11869 char passwd[64];
11870 char b64in[128];
11871 char b64out[256];
11872 char * headers[HTTPHEADCNT];
11873 int closecon = 0;
11874 int first = 1;
11875
11876 if (httpfd == -1)
11877 return(-1);
11878
11879 if (array) {
11880 for (i = 0; i < HTTPHEADCNT; i++)
11881 headers[i] = NULL;
11882 }
11883 len = 9; /* HEAD */
11884 len += strlen(HTTP_VERSION);
11885 len += strlen(remote);
11886 len += 16;
11887
11888 if ( hdrlist ) {
11889 for (i = 0; hdrlist[i]; i++)
11890 len += strlen(hdrlist[i]) + 2;
11891 }
11892 len += strlen(http_host_port) + 8;
11893
11894 if (agent)
11895 len += 13 + strlen(agent);
11896 if (user) {
11897 if (!pwd) {
11898 readpass("Password: ",passwd,64);
11899 pwd = passwd;
11900 }
11901 ckmakmsg(b64in,sizeof(b64in),user,":",pwd,NULL);
11902 j = b8tob64(b64in,strlen(b64in),b64out,256);
11903 memset(pwd,0,strlen(pwd)); /* NOT PORTABLE */
11904 if (j < 0)
11905 return(-1);
11906 b64out[j] = '\0';
11907 len += j + 24;
11908 }
11909 #ifdef HTTP_CLOSE
11910 len += 19; /* Connection: close */
11911 #endif
11912 len += 3; /* blank line + null */
11913
11914 request = (char *)malloc(len);
11915 if (!request)
11916 return(-1);
11917
11918 sprintf(request,"HEAD %s %s\r\n",remote,HTTP_VERSION);
11919 ckstrncat(request,"Host: ", len);
11920 ckstrncat(request,http_host_port, len);
11921 ckstrncat(request,"\r\n",len);
11922 if (agent) {
11923 ckstrncat(request,"User-agent: ",len);
11924 ckstrncat(request,agent,len);
11925 ckstrncat(request,"\r\n",len);
11926 }
11927 if (user) {
11928 ckstrncat(request,"Authorization: Basic ",len);
11929 ckstrncat(request,b64out,len);
11930 ckstrncat(request,"\r\n",len);
11931 }
11932 if ( hdrlist ) {
11933 for (i = 0; hdrlist[i]; i++) {
11934 ckstrncat(request,hdrlist[i],len);
11935 ckstrncat(request,"\r\n",len);
11936 }
11937 }
11938 #ifdef HTTP_CLOSE
11939 ckstrncat(request,"Connection: close\r\n",len);
11940 #endif
11941 ckstrncat(request,"\r\n",len);
11942
11943 if ( local && local[0] ) {
11944 if (!zopeno(ZOFILE,local,NULL,NULL)) {
11945 free(request);
11946 return(-1);
11947 }
11948 }
11949
11950 headreq:
11951 if (http_tol((CHAR *)request,strlen(request)) < 0)
11952 {
11953 http_close();
11954 if ( first ) {
11955 first--;
11956 http_reopen();
11957 goto headreq;
11958 }
11959 rc = -1;
11960 goto headexit;
11961 }
11962
11963 /* Process the headers */
11964
11965 local_t = time(NULL);
11966 nullline = 0;
11967 i = 0;
11968 while (!nullline && (ch = http_inc(0)) >= 0 && i < HTTPBUFLEN) {
11969 buf[i] = ch;
11970 if (buf[i] == 10) { /* found end of line */
11971 if (i > 0 && buf[i-1] == 13)
11972 i--;
11973 if (i < 1)
11974 nullline = 1;
11975 buf[i] = '\0';
11976 if (array && !nullline && hdcnt < HTTPHEADCNT)
11977 makestr(&headers[hdcnt++],buf);
11978 if (!ckstrcmp(buf,"HTTP",4,0)) {
11979 http_fnd = 1;
11980 j = ckindex(" ",buf,0,0,0);
11981 p = &buf[j];
11982 while (isspace(*p))
11983 p++;
11984 switch (p[0]) {
11985 case '1': /* Informational message */
11986 break;
11987 case '2': /* Success */
11988 break;
11989 case '3': /* Redirection */
11990 case '4': /* Client failure */
11991 case '5': /* Server failure */
11992 default: /* Unknown */
11993 if (!quiet)
11994 printf("Failure: Server reports %s\n",p);
11995 rc = -1;
11996 }
11997 http_set_code_reply(p);
11998 } else {
11999 if (!ckstrcmp(buf,"Connection:",11,0)) {
12000 if ( ckindex("close",buf,11,0,0) != 0 )
12001 closecon = 1;
12002 }
12003 if ( local && local[0] ) {
12004 zsout(ZOFILE,buf);
12005 zsout(ZOFILE,"\r\n");
12006 }
12007 if (stdio)
12008 printf("%s\r\n",buf);
12009 }
12010 i = 0;
12011 } else {
12012 i++;
12013 }
12014 }
12015 if (ch < 0 && first) {
12016 first--;
12017 http_close();
12018 http_reopen();
12019 goto headreq;
12020 }
12021 if ( http_fnd == 0 )
12022 rc = -1;
12023
12024 if (array)
12025 http_mkarray(headers,hdcnt,array);
12026
12027 headexit:
12028 if ( local && local[0] )
12029 zclose(ZOFILE);
12030 if (closecon)
12031 http_close();
12032 free(request);
12033 for (i = 0; i < hdcnt; i++) {
12034 if (headers[i])
12035 free(headers[i]);
12036 }
12037 return(rc);
12038 }
12039
12040 int
12041 #ifdef CK_ANSIC
http_index(char * agent,char ** hdrlist,char * user,char * pwd,char array,char * local,char * remote,int stdio)12042 http_index(char * agent, char ** hdrlist, char * user, char * pwd,
12043 char array, char * local, char * remote, int stdio)
12044 #else
12045 http_index(agent, hdrlist, user, pwd, array, local, remote, stdio)
12046 char * agent; char ** hdrlist; char * user; char * pwd;
12047 char array; char * local; char * remote; int stdio;
12048 #endif /* CK_ANSIC */
12049 {
12050 char * request = NULL;
12051 int i, j, len = 0, hdcnt = 0, rc = 0;
12052 int ch;
12053 int http_fnd = 0;
12054 char buf[HTTPBUFLEN], *p;
12055 int nullline;
12056 time_t mod_t;
12057 time_t srv_t;
12058 time_t local_t;
12059 char passwd[64];
12060 char b64in[128];
12061 char b64out[256];
12062 char * headers[HTTPHEADCNT];
12063 int closecon = 0;
12064 int chunked = 0;
12065 int zfile = 0;
12066 int first = 1;
12067
12068 if (httpfd == -1)
12069 return(-1);
12070
12071 if (array) {
12072 for (i = 0; i < HTTPHEADCNT; i++)
12073 headers[i] = NULL;
12074 }
12075 len = 10; /* INDEX */
12076 len += strlen(HTTP_VERSION);
12077 len += strlen(remote);
12078 len += 16;
12079
12080 if ( hdrlist ) {
12081 for (i = 0; hdrlist[i]; i++)
12082 len += strlen(hdrlist[i]) + 2;
12083 }
12084 len += strlen(http_host_port) + 8;
12085
12086 if (agent)
12087 len += 13 + strlen(agent);
12088 if (user) {
12089 if (!pwd) {
12090 readpass("Password: ",passwd,64);
12091 pwd = passwd;
12092 }
12093 ckmakmsg(b64in,sizeof(b64in),user,":",pwd,NULL);
12094 j = b8tob64(b64in,strlen(b64in),b64out,256);
12095 memset(pwd,0,strlen(pwd));
12096 if (j < 0)
12097 return(-1);
12098 b64out[j] = '\0';
12099 len += j + 24;
12100 }
12101 #ifdef HTTP_CLOSE
12102 len += 19; /* Connection: close */
12103 #endif
12104 len += 3; /* blank line + null */
12105
12106 request = malloc(len);
12107 if (!request)
12108 return(-1);
12109
12110 sprintf(request,"INDEX %s\r\n",HTTP_VERSION);
12111 ckstrncat(request,"Host: ", len);
12112 ckstrncat(request,http_host_port, len);
12113 ckstrncat(request,"\r\n",len);
12114 if (agent) {
12115 ckstrncat(request,"User-agent: ",len);
12116 ckstrncat(request,agent,len);
12117 ckstrncat(request,"\r\n",len);
12118 }
12119 if (user) {
12120 ckstrncat(request,"Authorization: Basic ",len);
12121 ckstrncat(request,b64out,len);
12122 ckstrncat(request,"\r\n",len);
12123 }
12124 if ( hdrlist ) {
12125 for (i = 0; hdrlist[i]; i++) {
12126 ckstrncat(request,hdrlist[i],len);
12127 ckstrncat(request,"\r\n",len);
12128 }
12129 }
12130 #ifdef HTTP_CLOSE
12131 ckstrncat(request,"Connection: close\r\n",len);
12132 #endif
12133 ckstrncat(request,"\r\n",len);
12134 indexreq:
12135 if (http_tol((CHAR *)request,strlen(request)) < 0)
12136 {
12137 http_close();
12138 if ( first ) {
12139 first--;
12140 http_reopen();
12141 goto indexreq;
12142 }
12143 rc = -1;
12144 goto indexexit;
12145 }
12146
12147 /* Process the headers */
12148 local_t = time(NULL);
12149 nullline = 0;
12150 i = 0;
12151 len = -1;
12152 while (!nullline && (ch = http_inc(0)) >= 0 && i < HTTPBUFLEN) {
12153 buf[i] = ch;
12154 if (buf[i] == 10) { /* found end of line */
12155 if (i > 0 && buf[i-1] == 13)
12156 i--;
12157 if (i < 1)
12158 nullline = 1;
12159 buf[i] = '\0';
12160 if (array && !nullline && hdcnt < HTTPHEADCNT)
12161 makestr(&headers[hdcnt++],buf);
12162 if (!ckstrcmp(buf,"HTTP",4,0)) {
12163 http_fnd = 1;
12164 j = ckindex(" ",buf,0,0,0);
12165 p = &buf[j];
12166 while (isspace(*p))
12167 p++;
12168 switch ( p[0] ) {
12169 case '1': /* Informational message */
12170 break;
12171 case '2': /* Success */
12172 break;
12173 case '3': /* Redirection */
12174 case '4': /* Client failure */
12175 case '5': /* Server failure */
12176 default: /* Unknown */
12177 if (!quiet)
12178 printf("Failure: Server reports %s\n",p);
12179 rc = -1;
12180 }
12181 http_set_code_reply(p);
12182 } else if ( !nullline ) {
12183 if (!ckstrcmp(buf,"Connection:",11,0)) {
12184 if ( ckindex("close",buf,11,0,0) != 0 )
12185 closecon = 1;
12186 } else if (!ckstrcmp(buf,"Content-Length:",15,0)) {
12187 len = atoi(&buf[16]);
12188 } else if (!ckstrcmp(buf,"Transfer-Encoding:",18,0)) {
12189 if ( ckindex("chunked",buf,18,0,0) != 0 )
12190 chunked = 1;
12191 debug(F101,"http_index chunked","",chunked);
12192 }
12193 printf("%s\n",buf);
12194 }
12195 i = 0;
12196 } else {
12197 i++;
12198 }
12199 }
12200
12201 if (ch < 0 && first) {
12202 first--;
12203 http_close();
12204 http_reopen();
12205 goto indexreq;
12206 }
12207 if ( http_fnd == 0 ) {
12208 rc = -1;
12209 closecon = 1;
12210 goto indexexit;
12211 }
12212
12213 /* Now we have the contents of the file */
12214 if ( local && local[0] ) {
12215 if (zopeno(ZOFILE,local,NULL,NULL))
12216 zfile = 1;
12217 else
12218 rc = -1;
12219 }
12220
12221 if ( chunked ) {
12222 while ((len = http_get_chunk_len()) > 0) {
12223 while (len && (ch = http_inc(0)) >= 0) {
12224 len--;
12225 if ( zfile )
12226 zchout(ZOFILE,(CHAR)ch);
12227 if ( stdio )
12228 conoc((CHAR)ch);
12229 }
12230 if ((ch = http_inc(0)) != CR)
12231 break;
12232 if ((ch = http_inc(0)) != LF)
12233 break;
12234 }
12235 } else {
12236 while (len && (ch = http_inc(0)) >= 0) {
12237 len--;
12238 if ( zfile )
12239 zchout(ZOFILE,(CHAR)ch);
12240 if ( stdio )
12241 conoc((CHAR)ch);
12242 }
12243 }
12244
12245 if ( zfile )
12246 zclose(ZOFILE);
12247
12248 if ( chunked ) { /* Parse Trailing Headers */
12249 nullline = 0;
12250 while (!nullline && (ch = http_inc(0)) >= 0 && i < HTTPBUFLEN) {
12251 buf[i] = ch;
12252 if ( buf[i] == 10 ) { /* found end of line */
12253 if (i > 0 && buf[i-1] == 13)
12254 i--;
12255 if (i < 1)
12256 nullline = 1;
12257 buf[i] = '\0';
12258 if (array && !nullline && hdcnt < HTTPHEADCNT)
12259 makestr(&headers[hdcnt++],buf);
12260 if (!ckstrcmp(buf,"Connection:",11,0)) {
12261 if ( ckindex("close",buf,11,0,0) != 0 )
12262 closecon = 1;
12263 }
12264 i = 0;
12265 } else {
12266 i++;
12267 }
12268 }
12269 }
12270 rc = 0;
12271
12272 indexexit:
12273 if (array)
12274 http_mkarray(headers,hdcnt,array);
12275
12276 if (closecon)
12277 http_close();
12278 free(request);
12279 for (i = 0; i < hdcnt; i++) {
12280 if (headers[i])
12281 free(headers[i]);
12282 }
12283 return(rc);
12284 }
12285
12286 int
12287 #ifdef CK_ANSIC
http_put(char * agent,char ** hdrlist,char * mime,char * user,char * pwd,char array,char * local,char * remote,char * dest,int stdio)12288 http_put(char * agent, char ** hdrlist, char * mime, char * user,
12289 char * pwd, char array, char * local, char * remote,
12290 char * dest, int stdio)
12291 #else
12292 http_put(agent, hdrlist, mime, user, pwd, array, local, remote, dest, stdio)
12293 char * agent; char ** hdrlist; char * mime; char * user;
12294 char * pwd; char array; char * local; char * remote; char * dest;
12295 int stdio;
12296 #endif /* CK_ANSIC */
12297 {
12298 char * request=NULL;
12299 int i, j, len = 0, hdcnt = 0, rc = 0;
12300 int ch;
12301 int http_fnd = 0;
12302 char buf[HTTPBUFLEN], *p;
12303 int nullline;
12304 time_t mod_t;
12305 time_t srv_t;
12306 time_t local_t;
12307 char passwd[64];
12308 char b64in[128];
12309 char b64out[256];
12310 int filelen;
12311 char * headers[HTTPHEADCNT];
12312 int closecon = 0;
12313 int chunked = 0;
12314 int first = 1;
12315 int zfile = 0;
12316
12317 if (httpfd == -1)
12318 return(-1);
12319 if (!mime) mime = "";
12320 if (!remote) remote = "";
12321 if (!local) local = "";
12322 if (!*local) return(-1);
12323
12324 if (array) {
12325 for (i = 0; i < HTTPHEADCNT; i++)
12326 headers[i] = NULL;
12327 }
12328 filelen = zchki(local);
12329 if (filelen < 0)
12330 return(-1);
12331
12332 /* Compute length of request header */
12333 len = 8; /* PUT */
12334 len += strlen(HTTP_VERSION);
12335 len += strlen(remote);
12336 len += 16;
12337
12338 if ( hdrlist ) {
12339 for (i = 0; hdrlist[i]; i++)
12340 len += strlen(hdrlist[i]) + 2;
12341 }
12342 len += strlen(http_host_port) + 8;
12343
12344 if (agent)
12345 len += 13 + strlen(agent);
12346 if (user) {
12347 if (!pwd) {
12348 readpass("Password: ",passwd,64);
12349 pwd = passwd;
12350 }
12351 ckmakmsg(b64in,sizeof(b64in),user,":",pwd,NULL);
12352 j = b8tob64(b64in,strlen(b64in),b64out,256);
12353 memset(pwd,0,strlen(pwd));
12354 if (j < 0)
12355 return(-1);
12356 b64out[j] = '\0';
12357 len += j + 24;
12358 }
12359 len += 16 + strlen(mime); /* Content-type: */
12360 len += 32; /* Content-length: */
12361 len += 32; /* Date: */
12362 #ifdef HTTP_CLOSE
12363 len += 19; /* Connection: close */
12364 #endif
12365 len += 3; /* blank line + null */
12366
12367 request = malloc(len);
12368 if (!request)
12369 return(-1);
12370
12371 sprintf(request,"PUT %s %s\r\n",remote,HTTP_VERSION);
12372 ckstrncat(request,"Date: ",len);
12373 #ifdef CMDATE2TM
12374 ckstrncat(request,http_now(),len);
12375 #else
12376 ckstrncat(request,...,len);
12377 #endif /* CMDATE2TM */
12378 ckstrncat(request,"\r\n",len);
12379 ckstrncat(request,"Host: ", len);
12380 ckstrncat(request,http_host_port, len);
12381 ckstrncat(request,"\r\n",len);
12382 if (agent) {
12383 ckstrncat(request,"User-agent: ",len);
12384 ckstrncat(request,agent,len);
12385 ckstrncat(request,"\r\n",len);
12386 }
12387 if (user) {
12388 ckstrncat(request,"Authorization: Basic ",len);
12389 ckstrncat(request,b64out,len);
12390 ckstrncat(request,"\r\n",len);
12391 }
12392 if ( hdrlist ) {
12393 for (i = 0; hdrlist[i]; i++) {
12394 ckstrncat(request,hdrlist[i],len);
12395 ckstrncat(request,"\r\n",len);
12396 }
12397 }
12398 ckstrncat(request,"Content-type: ",len);
12399 ckstrncat(request,mime,len);
12400 ckstrncat(request,"\r\n",len);
12401 sprintf(buf,"Content-length: %d\r\n",filelen); /* safe */
12402 ckstrncat(request,buf,len);
12403 #ifdef HTTP_CLOSE
12404 ckstrncat(request,"Connection: close\r\n",len);
12405 #endif
12406 ckstrncat(request,"\r\n",len);
12407
12408 /* Now we have the contents of the file */
12409 if (zopeni(ZIFILE,local)) {
12410
12411 putreq: /* Send request */
12412 if (http_tol((CHAR *)request,strlen(request)) <= 0) {
12413 http_close();
12414 if ( first ) {
12415 first--;
12416 http_reopen();
12417 goto putreq;
12418 }
12419 zclose(ZIFILE);
12420 rc = -1;
12421 goto putexit;
12422 }
12423 /* Request headers have been sent */
12424
12425 i = 0;
12426 while (zchin(ZIFILE,&ch) == 0) {
12427 buf[i++] = ch;
12428 if (i == HTTPBUFLEN) {
12429 if (http_tol((CHAR *)buf,HTTPBUFLEN) <= 0) {
12430 http_close();
12431 if ( first ) {
12432 first--;
12433 http_reopen();
12434 goto putreq;
12435 }
12436 }
12437 i = 0;
12438 }
12439 }
12440 if (i > 0) {
12441 if (http_tol((CHAR *)buf,i) < 0) {
12442 http_close();
12443 if ( first ) {
12444 first--;
12445 http_reopen();
12446 goto putreq;
12447 }
12448 }
12449 }
12450 zclose(ZIFILE);
12451
12452 /* Process the response headers */
12453 local_t = time(NULL);
12454 nullline = 0;
12455 i = 0;
12456 len = -1;
12457 while (!nullline && (ch = http_inc(0)) >= 0 && i < HTTPBUFLEN) {
12458 buf[i] = ch;
12459 if (buf[i] == 10) { /* found end of line */
12460 if (i > 0 && buf[i-1] == 13)
12461 i--;
12462 if (i < 1)
12463 nullline = 1;
12464 buf[i] = '\0';
12465 if (array && !nullline && hdcnt < HTTPHEADCNT)
12466 makestr(&headers[hdcnt++],buf);
12467 if (!ckstrcmp(buf,"HTTP",4,0)) {
12468 http_fnd = 1;
12469 j = ckindex(" ",buf,0,0,0);
12470 p = &buf[j];
12471 while (isspace(*p))
12472 p++;
12473 switch (p[0]) {
12474 case '1': /* Informational message */
12475 break;
12476 case '2': /* Success */
12477 break;
12478 case '3': /* Redirection */
12479 case '4': /* Client failure */
12480 case '5': /* Server failure */
12481 default: /* Unknown */
12482 if (!quiet)
12483 printf("Failure: Server reports %s\n",p);
12484 rc = -1;
12485 }
12486 http_set_code_reply(p);
12487 } else {
12488 if (!ckstrcmp(buf,"Connection:",11,0)) {
12489 if ( ckindex("close",buf,11,0,0) != 0 )
12490 closecon = 1;
12491 } else if (!ckstrcmp(buf,"Content-Length:",15,0)) {
12492 len = atoi(&buf[16]);
12493 } else if (!ckstrcmp(buf,"Transfer-Encoding:",18,0)) {
12494 if ( ckindex("chunked",buf,18,0,0) != 0 )
12495 chunked = 1;
12496 debug(F101,"http_put chunked","",chunked);
12497 }
12498 if ( stdio )
12499 printf("%s\n",buf);
12500 }
12501 i = 0;
12502 } else {
12503 i++;
12504 }
12505 }
12506 if (ch < 0 && first) {
12507 first--;
12508 http_close();
12509 http_reopen();
12510 goto putreq;
12511 }
12512 if ( http_fnd == 0 ) {
12513 closecon = 1;
12514 rc = -1;
12515 goto putexit;
12516 }
12517
12518 /* Any response data? */
12519 if ( dest && dest[0] ) {
12520 if (zopeno(ZOFILE,dest,NULL,NULL))
12521 zfile = 1;
12522 else
12523 rc = -1;
12524 }
12525
12526 if ( chunked ) {
12527 while ((len = http_get_chunk_len()) > 0) {
12528 while (len && (ch = http_inc(0)) >= 0) {
12529 len--;
12530 if ( zfile )
12531 zchout(ZOFILE,(CHAR)ch);
12532 if ( stdio )
12533 conoc((CHAR)ch);
12534 }
12535 if ((ch = http_inc(0)) != CR)
12536 break;
12537 if ((ch = http_inc(0)) != LF)
12538 break;
12539 }
12540 } else {
12541 while (len && (ch = http_inc(0)) >= 0) {
12542 len--;
12543 if ( zfile )
12544 zchout(ZOFILE,(CHAR)ch);
12545 if ( stdio )
12546 conoc((CHAR)ch);
12547 }
12548 }
12549
12550 if ( zfile )
12551 zclose(ZOFILE);
12552
12553 if ( chunked ) { /* Parse Trailing Headers */
12554 nullline = 0;
12555 while (!nullline && (ch = http_inc(0)) >= 0 && i < HTTPBUFLEN) {
12556 buf[i] = ch;
12557 if ( buf[i] == 10 ) { /* found end of line */
12558 if (i > 0 && buf[i-1] == 13)
12559 i--;
12560 if (i < 1)
12561 nullline = 1;
12562 buf[i] = '\0';
12563 if (array && !nullline && hdcnt < HTTPHEADCNT)
12564 makestr(&headers[hdcnt++],buf);
12565 if (!ckstrcmp(buf,"Connection:",11,0)) {
12566 if ( ckindex("close",buf,11,0,0) != 0 )
12567 closecon = 1;
12568 }
12569 i = 0;
12570 } else {
12571 i++;
12572 }
12573 }
12574 }
12575 } else {
12576 rc = -1;
12577 }
12578
12579 putexit:
12580 if ( array )
12581 http_mkarray(headers,hdcnt,array);
12582
12583 if (closecon)
12584 http_close();
12585 free(request);
12586 for (i = 0; i < hdcnt; i++) {
12587 if (headers[i])
12588 free(headers[i]);
12589 }
12590 return(rc);
12591 }
12592
12593 int
12594 #ifdef CK_ANSIC
http_delete(char * agent,char ** hdrlist,char * user,char * pwd,char array,char * remote)12595 http_delete(char * agent, char ** hdrlist, char * user,
12596 char * pwd, char array, char * remote)
12597 #else
12598 http_delete(agent, hdrlist, user, pwd, array, remote)
12599 char * agent; char ** hdrlist; char * user;
12600 char * pwd; char array; char * remote;
12601 #endif /* CK_ANSIC */
12602 {
12603 char * request=NULL;
12604 int i, j, len = 0, hdcnt = 0, rc = 0;
12605 int ch;
12606 int http_fnd = 0;
12607 char buf[HTTPBUFLEN], *p;
12608 int nullline;
12609 time_t mod_t;
12610 time_t srv_t;
12611 time_t local_t;
12612 char passwd[64];
12613 char b64in[128];
12614 char b64out[256];
12615 char * headers[HTTPHEADCNT];
12616 int closecon = 0;
12617 int chunked = 0;
12618 int first = 1;
12619
12620 if (httpfd == -1)
12621 return(-1);
12622
12623 if (array) {
12624 for (i = 0; i < HTTPHEADCNT; i++)
12625 headers[i] = NULL;
12626 }
12627
12628 /* Compute length of request header */
12629 len = 11; /* DELETE */
12630 len += strlen(HTTP_VERSION);
12631 len += strlen(remote);
12632 len += 16;
12633
12634 if ( hdrlist ) {
12635 for (i = 0; hdrlist[i]; i++)
12636 len += strlen(hdrlist[i]) + 2;
12637 }
12638 len += strlen(http_host_port) + 8;
12639
12640 if (agent)
12641 len += 13 + strlen(agent);
12642 if (user) {
12643 if (!pwd) {
12644 readpass("Password: ",passwd,64);
12645 pwd = passwd;
12646 }
12647 ckmakmsg(b64in,sizeof(b64in),user,":",pwd,NULL);
12648 j = b8tob64(b64in,strlen(b64in),b64out,256);
12649 memset(pwd,0,strlen(pwd));
12650 if (j < 0)
12651 return(-1);
12652 b64out[j] = '\0';
12653 len += j + 24;
12654 }
12655 len += 32; /* Date: */
12656 #ifdef HTTP_CLOSE
12657 len += 19; /* Connection: close */
12658 #endif
12659 len += 3; /* blank line + null */
12660
12661 request = malloc(len);
12662 if (!request)
12663 return(-1);
12664
12665 sprintf(request,"DELETE %s %s\r\n",remote,HTTP_VERSION);
12666 ckstrncat(request,"Date: ",len);
12667 #ifdef CMDATE2TM
12668 ckstrncat(request,http_now(),len);
12669 #else
12670 ckstrncat(request,...,len);
12671 #endif /* CMDATE2TM */
12672 ckstrncat(request,"\r\n",len);
12673 ckstrncat(request,"Host: ", len);
12674 ckstrncat(request,http_host_port, len);
12675 ckstrncat(request,"\r\n",len);
12676 if (agent) {
12677 ckstrncat(request,"User-agent: ",len);
12678 ckstrncat(request,agent,len);
12679 ckstrncat(request,"\r\n",len);
12680 }
12681 if (user) {
12682 ckstrncat(request,"Authorization: Basic ",len);
12683 ckstrncat(request,b64out,len);
12684 ckstrncat(request,"\r\n",len);
12685 }
12686 if ( hdrlist ) {
12687 for (i = 0; hdrlist[i]; i++) {
12688 ckstrncat(request,hdrlist[i],len);
12689 ckstrncat(request,"\r\n",len);
12690 }
12691 }
12692 #ifdef HTTP_CLOSE
12693 ckstrncat(request,"Connection: close\r\n",len);
12694 #endif
12695 ckstrncat(request,"\r\n",len);
12696 delreq:
12697 if (http_tol((CHAR *)request,strlen(request)) < 0)
12698 {
12699 http_close();
12700 if ( first ) {
12701 first--;
12702 http_reopen();
12703 goto delreq;
12704 }
12705 rc = -1;
12706 goto delexit;
12707 }
12708
12709 /* Process the response headers */
12710 local_t = time(NULL);
12711 nullline = 0;
12712 i = 0;
12713 len = -1;
12714 while (!nullline && (ch = http_inc(0)) >= 0 && i < HTTPBUFLEN) {
12715 buf[i] = ch;
12716 if (buf[i] == 10) { /* found end of line */
12717 if (i > 0 && buf[i-1] == 13)
12718 i--;
12719 if (i < 1)
12720 nullline = 1;
12721 buf[i] = '\0';
12722 if (array && !nullline && hdcnt < HTTPHEADCNT)
12723 makestr(&headers[hdcnt++],buf);
12724 if (!ckstrcmp(buf,"HTTP",4,0)) {
12725 http_fnd = 1;
12726 j = ckindex(" ",buf,0,0,0);
12727 p = &buf[j];
12728 while (isspace(*p))
12729 p++;
12730 switch (p[0]) {
12731 case '1': /* Informational message */
12732 break;
12733 case '2': /* Success */
12734 break;
12735 case '3': /* Redirection */
12736 case '4': /* Client failure */
12737 case '5': /* Server failure */
12738 default: /* Unknown */
12739 if (!quiet)
12740 printf("Failure: Server reports %s\n",p);
12741 rc = -1;
12742 }
12743 http_set_code_reply(p);
12744 } else {
12745 if (!ckstrcmp(buf,"Connection:",11,0)) {
12746 if ( ckindex("close",buf,11,0,0) != 0 )
12747 closecon = 1;
12748 } else if (!ckstrcmp(buf,"Content-Length:",15,0)) {
12749 len = atoi(&buf[16]);
12750 } else if (!ckstrcmp(buf,"Transfer-Encoding:",18,0)) {
12751 if ( ckindex("chunked",buf,18,0,0) != 0 )
12752 chunked = 1;
12753 debug(F101,"http_delete chunked","",chunked);
12754 }
12755 printf("%s\n",buf);
12756 }
12757 i = 0;
12758 } else {
12759 i++;
12760 }
12761 }
12762 if (ch < 0 && first) {
12763 first--;
12764 http_close();
12765 http_reopen();
12766 goto delreq;
12767 }
12768 if ( http_fnd == 0 ) {
12769 rc = -1;
12770 closecon = 1;
12771 goto delexit;
12772 }
12773
12774 /* Any response data? */
12775 if ( chunked ) {
12776 while ((len = http_get_chunk_len()) > 0) {
12777 while (len && (ch = http_inc(0)) >= 0) {
12778 len--;
12779 conoc((CHAR)ch);
12780 }
12781 if ((ch = http_inc(0)) != CR)
12782 break;
12783 if ((ch = http_inc(0)) != LF)
12784 break;
12785 }
12786 } else {
12787 while (len && (ch = http_inc(0)) >= 0) {
12788 len--;
12789 conoc((CHAR)ch);
12790 }
12791 }
12792
12793 if ( chunked ) { /* Parse Trailing Headers */
12794 nullline = 0;
12795 while (!nullline && (ch = http_inc(0)) >= 0 && i < HTTPBUFLEN) {
12796 buf[i] = ch;
12797 if ( buf[i] == 10 ) { /* found end of line */
12798 if (i > 0 && buf[i-1] == 13)
12799 i--;
12800 if (i < 1)
12801 nullline = 1;
12802 buf[i] = '\0';
12803 if (array && !nullline && hdcnt < HTTPHEADCNT)
12804 makestr(&headers[hdcnt++],buf);
12805 if (!ckstrcmp(buf,"Connection:",11,0)) {
12806 if ( ckindex("close",buf,11,0,0) != 0 )
12807 closecon = 1;
12808 }
12809 i = 0;
12810 } else {
12811 i++;
12812 }
12813 }
12814 }
12815
12816 delexit:
12817 if (array)
12818 http_mkarray(headers,hdcnt,array);
12819
12820 if (closecon)
12821 http_close();
12822 free(request);
12823 for (i = 0; i < hdcnt; i++) {
12824 if (headers[i])
12825 free(headers[i]);
12826 }
12827 return(rc);
12828 }
12829
12830 int
12831 #ifdef CK_ANSIC
http_post(char * agent,char ** hdrlist,char * mime,char * user,char * pwd,char array,char * local,char * remote,char * dest,int stdio)12832 http_post(char * agent, char ** hdrlist, char * mime, char * user,
12833 char * pwd, char array, char * local, char * remote,
12834 char * dest, int stdio)
12835 #else
12836 http_post(agent, hdrlist, mime, user, pwd, array, local, remote, dest,
12837 stdio)
12838 char * agent; char ** hdrlist; char * mime; char * user;
12839 char * pwd; char array; char * local; char * remote; char * dest;
12840 int stdio;
12841 #endif /* CK_ANSIC */
12842 {
12843 char * request=NULL;
12844 int i, j, len = 0, hdcnt = 0, rc = 0;
12845 int ch;
12846 int http_fnd = 0;
12847 char buf[HTTPBUFLEN], *p;
12848 int nullline;
12849 time_t mod_t;
12850 time_t srv_t;
12851 time_t local_t;
12852 char passwd[64];
12853 char b64in[128];
12854 char b64out[256];
12855 int filelen;
12856 char * headers[HTTPHEADCNT];
12857 int closecon = 0;
12858 int chunked = 0;
12859 int zfile = 0;
12860 int first = 1;
12861
12862 if (httpfd == -1)
12863 return(-1);
12864
12865 if (array) {
12866 for (i = 0; i < HTTPHEADCNT; i++)
12867 headers[i] = NULL;
12868 }
12869 filelen = zchki(local);
12870 if (filelen < 0)
12871 return(-1);
12872
12873 /* Compute length of request header */
12874 len = 9; /* POST */
12875 len += strlen(HTTP_VERSION);
12876 len += strlen(remote);
12877 len += 16;
12878
12879 if ( hdrlist ) {
12880 for (i = 0; hdrlist[i]; i++)
12881 len += strlen(hdrlist[i]) + 2;
12882 }
12883 len += strlen(http_host_port) + 8;
12884
12885 if (agent)
12886 len += 13 + strlen(agent);
12887 if (user) {
12888 if (!pwd) {
12889 readpass("Password: ",passwd,64);
12890 pwd = passwd;
12891 }
12892 ckmakmsg(b64in,sizeof(b64in),user,":",pwd,NULL);
12893 j = b8tob64(b64in,strlen(b64in),b64out,256);
12894 memset(pwd,0,strlen(pwd));
12895 if (j < 0)
12896 return(-1);
12897 b64out[j] = '\0';
12898 len += j + 24;
12899 }
12900 len += 16 + strlen(mime); /* Content-type: */
12901 len += 32; /* Content-length: */
12902 len += 32; /* Date: */
12903 #ifdef HTTP_CLOSE
12904 len += 19; /* Connection: close */
12905 #endif
12906 len += 3; /* blank line + null */
12907
12908 request = malloc(len);
12909 if (!request)
12910 return(-1);
12911
12912 sprintf(request,"POST %s %s\r\n",remote,HTTP_VERSION);
12913 ckstrncat(request,"Date: ",len);
12914 ckstrncat(request,http_now(),len);
12915 ckstrncat(request,"\r\n",len);
12916 ckstrncat(request,"Host: ", len);
12917 ckstrncat(request,http_host_port, len);
12918 ckstrncat(request,"\r\n",len);
12919 if (agent) {
12920 ckstrncat(request,"User-agent: ",len);
12921 ckstrncat(request,agent,len);
12922 ckstrncat(request,"\r\n",len);
12923 }
12924 if (user) {
12925 ckstrncat(request,"Authorization: Basic ",len);
12926 ckstrncat(request,b64out,len);
12927 ckstrncat(request,"\r\n",len);
12928 }
12929 if ( hdrlist ) {
12930 for (i = 0; hdrlist[i]; i++) {
12931 ckstrncat(request,hdrlist[i],len);
12932 ckstrncat(request,"\r\n",len);
12933 }
12934 }
12935 ckstrncat(request,"Content-type: ",len);
12936 ckstrncat(request,mime,len);
12937 ckstrncat(request,"\r\n",len);
12938 #ifdef HTTP_CLOSE
12939 ckstrncat(request,"Connection: close\r\n",len);
12940 #endif
12941 sprintf(buf,"Content-length: %d\r\n",filelen); /* safe */
12942 ckstrncat(request,buf,len);
12943 ckstrncat(request,"\r\n",len);
12944 #ifdef COMMENT
12945 /* This is apparently a mistake - the previous ckstrncat() already */
12946 /* appended a blank line to the request. There should only be one. */
12947 /* Servers are not required by RFC 2616 to ignore extraneous empty */
12948 /* lines. -fdc, 28 Aug 2005. */
12949 ckstrncat(request,"\r\n",len);
12950 #endif /* COMMENT */
12951
12952 /* Now we have the contents of the file */
12953 postopen:
12954 if (zopeni(ZIFILE,local)) {
12955 postreq:
12956 if (http_tol((CHAR *)request,strlen(request)) < 0)
12957 {
12958 http_close();
12959 if ( first ) {
12960 first--;
12961 http_reopen();
12962 goto postreq;
12963 }
12964 rc = -1;
12965 zclose(ZIFILE);
12966 goto postexit;
12967 }
12968
12969 i = 0;
12970 while (zchin(ZIFILE,&ch) == 0) {
12971 buf[i++] = ch;
12972 if (i == HTTPBUFLEN) {
12973 http_tol((CHAR *)buf,HTTPBUFLEN);
12974 i = 0;
12975 }
12976 }
12977 if (i > 0)
12978 http_tol((CHAR *)buf,HTTPBUFLEN);
12979 zclose(ZIFILE);
12980
12981 /* Process the response headers */
12982 local_t = time(NULL);
12983 nullline = 0;
12984 i = 0;
12985 len = -1;
12986 while (!nullline && (ch = http_inc(0)) >= 0 && i < HTTPBUFLEN) {
12987 buf[i] = ch;
12988 if (buf[i] == 10) { /* found end of line */
12989 if (i > 0 && buf[i-1] == 13)
12990 i--;
12991 if (i < 1)
12992 nullline = 1;
12993 buf[i] = '\0';
12994 if (array && !nullline && hdcnt < HTTPHEADCNT)
12995 makestr(&headers[hdcnt++],buf);
12996 if (!ckstrcmp(buf,"HTTP",4,0)) {
12997 http_fnd = 1;
12998 j = ckindex(" ",buf,0,0,0);
12999 p = &buf[j];
13000 while (isspace(*p))
13001 p++;
13002 switch (p[0]) {
13003 case '1': /* Informational message */
13004 break;
13005 case '2': /* Success */
13006 break;
13007 case '3': /* Redirection */
13008 case '4': /* Client failure */
13009 case '5': /* Server failure */
13010 default: /* Unknown */
13011 if (!quiet)
13012 printf("Failure: Server reports %s\n",p);
13013 rc = -1;
13014 }
13015 http_set_code_reply(p);
13016 } else {
13017 if (!ckstrcmp(buf,"Connection:",11,0)) {
13018 if ( ckindex("close",buf,11,0,0) != 0 )
13019 closecon = 1;
13020 } else if (!ckstrcmp(buf,"Content-Length:",15,0)) {
13021 len = atoi(&buf[16]);
13022 } else if (!ckstrcmp(buf,"Transfer-Encoding:",18,0)) {
13023 if ( ckindex("chunked",buf,18,0,0) != 0 )
13024 chunked = 1;
13025 debug(F101,"http_post chunked","",chunked);
13026 }
13027 if (stdio)
13028 printf("%s\n",buf);
13029 }
13030 i = 0;
13031 } else {
13032 i++;
13033 }
13034 }
13035 if (ch < 0 && first) {
13036 first--;
13037 http_close();
13038 http_reopen();
13039 goto postopen;
13040 }
13041 if (http_fnd == 0) {
13042 rc = -1;
13043 closecon = 1;
13044 goto postexit;
13045 }
13046
13047 /* Any response data? */
13048 if ( dest && dest[0] ) {
13049 if (zopeno(ZOFILE,dest,NULL,NULL))
13050 zfile = 1;
13051 else
13052 rc = -1;
13053 }
13054
13055 if ( chunked ) {
13056 while ((len = http_get_chunk_len()) > 0) {
13057 while (len && (ch = http_inc(0)) >= 0) {
13058 len--;
13059 if ( zfile )
13060 zchout(ZOFILE,(CHAR)ch);
13061 if ( stdio )
13062 conoc((CHAR)ch);
13063 }
13064 if ((ch = http_inc(0)) != CR)
13065 break;
13066 if ((ch = http_inc(0)) != LF)
13067 break;
13068 }
13069 } else {
13070 while (len && (ch = http_inc(0)) >= 0) {
13071 len--;
13072 if ( zfile )
13073 zchout(ZOFILE,(CHAR)ch);
13074 if ( stdio )
13075 conoc((CHAR)ch);
13076 }
13077 }
13078
13079 if ( zfile )
13080 zclose(ZOFILE);
13081
13082 if ( chunked ) { /* Parse Trailing Headers */
13083 nullline = 0;
13084 while (!nullline && (ch = http_inc(0)) >= 0 && i < HTTPBUFLEN) {
13085 buf[i] = ch;
13086 if ( buf[i] == 10 ) { /* found end of line */
13087 if (i > 0 && buf[i-1] == 13)
13088 i--;
13089 if (i < 1)
13090 nullline = 1;
13091 buf[i] = '\0';
13092 if (array && !nullline && hdcnt < HTTPHEADCNT)
13093 makestr(&headers[hdcnt++],buf);
13094 if (!ckstrcmp(buf,"Connection:",11,0)) {
13095 if ( ckindex("close",buf,11,0,0) != 0 )
13096 closecon = 1;
13097 }
13098 i = 0;
13099 } else {
13100 i++;
13101 }
13102 }
13103 }
13104 } else {
13105 rc = -1;
13106 }
13107
13108 postexit:
13109 if (array)
13110 http_mkarray(headers,hdcnt,array);
13111 if (closecon)
13112 http_close();
13113 free(request);
13114 for (i = 0; i < hdcnt; i++) {
13115 if (headers[i])
13116 free(headers[i]);
13117 }
13118 return(rc);
13119 }
13120
13121 int
13122 #ifdef CK_ANSIC
http_connect(int socket,char * agent,char ** hdrlist,char * user,char * pwd,char array,char * host_port)13123 http_connect(int socket, char * agent, char ** hdrlist, char * user,
13124 char * pwd, char array, char * host_port)
13125 #else
13126 http_connect(socket, agent, hdrlist, user, pwd, array, host_port)
13127 int socket;
13128 char * agent; char ** hdrlist; char * user;
13129 char * pwd; char array; char * host_port;
13130 #endif /* CK_ANSIC */
13131 {
13132 char * request=NULL;
13133 int i, j, len = 0, hdcnt = 0, rc = 0;
13134 int http_fnd = 0;
13135 char buf[HTTPBUFLEN], *p, ch;
13136 int nullline;
13137 time_t mod_t;
13138 time_t srv_t;
13139 time_t local_t;
13140 char passwd[64];
13141 char b64in[128];
13142 char b64out[256];
13143 char * headers[HTTPHEADCNT];
13144 int connected = 0;
13145
13146 tcp_http_proxy_errno = 0;
13147
13148 if (socket == -1)
13149 return(-1);
13150
13151 if (array) {
13152 for (i = 0; i < HTTPHEADCNT; i++)
13153 headers[i] = NULL;
13154 }
13155
13156 /* Compute length of request header */
13157 len = 12; /* CONNECT */
13158 len += strlen(HTTP_VERSION);
13159 len += strlen(host_port);
13160 len += (int) strlen(http_host_port) + 8;
13161 len += 16;
13162 len += strlen("Proxy-Connection: Keep-Alive\r\n");
13163 if ( hdrlist ) {
13164 for (i = 0; hdrlist[i]; i++)
13165 len += strlen(hdrlist[i]) + 2;
13166 }
13167 if (agent && agent[0])
13168 len += 13 + strlen(agent);
13169 if (user && user[0]) {
13170 if (!pwd) {
13171 readpass("Password: ",passwd,64);
13172 pwd = passwd;
13173 }
13174 ckmakmsg(b64in,sizeof(b64in),user,":",pwd,NULL);
13175 j = b8tob64(b64in,strlen(b64in),b64out,256);
13176 memset(pwd,0,strlen(pwd));
13177 if (j < 0)
13178 return(-1);
13179 b64out[j] = '\0';
13180 len += j + 72;
13181 }
13182 len += 32; /* Date: */
13183 len += 3; /* blank line + null */
13184
13185 request = malloc(len);
13186 if (!request)
13187 return(-1);
13188
13189 sprintf(request,"CONNECT %s %s\r\n",host_port,HTTP_VERSION);
13190 ckstrncat(request,"Date: ",len);
13191 #ifdef CMDATE2TM
13192 ckstrncat(request,http_now(),len);
13193 #else
13194 strcat(request,...);
13195 #endif /* CMDATE2TM */
13196 ckstrncat(request,"\r\n",len);
13197 ckstrncat(request,"Host: ", len);
13198 ckstrncat(request,http_host_port, len);
13199 ckstrncat(request,"\r\n",len);
13200 if (agent && agent[0]) {
13201 ckstrncat(request,"User-agent: ",len);
13202 ckstrncat(request,agent,len);
13203 ckstrncat(request,"\r\n",len);
13204 }
13205 if (user && user[0]) {
13206 ckstrncat(request,"Proxy-authorization: Basic ",len);
13207 ckstrncat(request,b64out,len);
13208 ckstrncat(request,"\r\n",len);
13209 ckstrncat(request,"Extension: Security/Remote-Passphrase\r\n",len);
13210 }
13211 ckstrncat(request,"Proxy-Connection: Keep-Alive\r\n",len);
13212 if ( hdrlist ) {
13213 for (i = 0; hdrlist[i]; i++) {
13214 ckstrncat(request,hdrlist[i],len);
13215 ckstrncat(request,"\r\n",len);
13216 }
13217 }
13218 ckstrncat(request,"\r\n",len);
13219 len = strlen(request);
13220
13221 #ifdef TCPIPLIB
13222 /* Send request */
13223 if (socket_write(socket,(CHAR *)request,strlen(request)) < 0) {
13224 rc = -1;
13225 goto connexit;
13226 }
13227 #else
13228 if (write(socket,(CHAR *)request,strlen(request)) < 0) { /* Send request */
13229 rc = -1;
13230 goto connexit;
13231 }
13232 #endif /* TCPIPLIB */
13233
13234 /* Process the response headers */
13235 local_t = time(NULL);
13236 nullline = 0;
13237 i = 0;
13238 while (!nullline &&
13239 #ifdef TCPIPLIB
13240 (socket_read(socket,&ch,1) == 1) &&
13241 #else
13242 (read(socket,&ch,1) == 1) &&
13243 #endif /* TCPIPLIB */
13244 i < HTTPBUFLEN) {
13245 buf[i] = ch;
13246 if (buf[i] == 10) { /* found end of line */
13247 if (i > 0 && buf[i-1] == 13)
13248 i--;
13249 if (i < 1)
13250 nullline = 1;
13251 buf[i] = '\0';
13252
13253 if (array && !nullline && hdcnt < HTTPHEADCNT)
13254 makestr(&headers[hdcnt++],buf);
13255 if (!ckstrcmp(buf,"HTTP",4,0)) {
13256 http_fnd = 1;
13257 j = ckindex(" ",buf,0,0,0);
13258 p = &buf[j];
13259 while (isspace(*p))
13260 p++;
13261 tcp_http_proxy_errno = atoi(p);
13262 switch (p[0]) {
13263 case '1': /* Informational message */
13264 break;
13265 case '2': /* Success */
13266 connected = 1;
13267 break;
13268 case '3': /* Redirection */
13269 case '4': /* Client failure */
13270 case '5': /* Server failure */
13271 default: /* Unknown */
13272 if (!quiet)
13273 printf("Failure: Server reports %s\n",p);
13274 rc = -1;
13275 }
13276 http_set_code_reply(p);
13277 } else {
13278 printf("%s\n",buf);
13279 }
13280 i = 0;
13281 } else {
13282 i++;
13283 }
13284 }
13285 if ( http_fnd == 0 )
13286 rc = -1;
13287
13288 if (array)
13289 http_mkarray(headers,hdcnt,array);
13290
13291 connexit:
13292 if ( !connected ) {
13293 if ( socket == ttyfd ) {
13294 ttclos(0);
13295 }
13296 else if ( socket == httpfd ) {
13297 http_close();
13298 }
13299 }
13300
13301 free(request);
13302 for (i = 0; i < hdcnt; i++) {
13303 if (headers[i])
13304 free(headers[i]);
13305 }
13306 return(rc);
13307 }
13308 #endif /* NOHTTP */
13309
13310 #ifdef CK_DNS_SRV
13311
13312 #define INCR_CHECK(x,y) x += y; if (x > size + answer.bytes) goto dnsout
13313 #define CHECK(x,y) if (x + y > size + answer.bytes) goto dnsout
13314 #define NTOHSP(x,y) x[0] << 8 | x[1]; x += y
13315
13316 #ifndef CKQUERYTYPE
13317 #ifdef UNIXWARE
13318 #ifndef UW7
13319 #define CKQUERYTYPE CHAR
13320 #endif /* UW7 */
13321 #endif /* UNIXWARE */
13322 #endif /* CKQUERYTYPE */
13323
13324 #ifndef CKQUERYTYPE
13325 #define CKQUERYTYPE char
13326 #endif /* CKQUERYTYPE */
13327
13328 /* 1 is success, 0 is failure */
13329 int
locate_srv_dns(host,service,protocol,addr_pp,naddrs)13330 locate_srv_dns(host, service, protocol, addr_pp, naddrs)
13331 char *host;
13332 char *service;
13333 char *protocol;
13334 struct sockaddr **addr_pp;
13335 int *naddrs;
13336 {
13337 int nout, j, count;
13338 union {
13339 unsigned char bytes[2048];
13340 HEADER hdr;
13341 } answer;
13342 unsigned char *p=NULL;
13343 CKQUERYTYPE query[MAX_DNS_NAMELEN];
13344 #ifdef CK_ANSIC
13345 const char * h;
13346 #else
13347 char * h;
13348 #endif /* CK_ANSIC */
13349 struct sockaddr *addr = NULL;
13350 struct sockaddr_in *sin = NULL;
13351 struct hostent *hp = NULL;
13352 int type, class;
13353 int priority, weight, size, len, numanswers, numqueries, rdlen;
13354 unsigned short port;
13355 #ifdef CK_ANSIC
13356 const
13357 #endif /* CK_ANSIC */
13358 int hdrsize = sizeof(HEADER);
13359 struct srv_dns_entry {
13360 struct srv_dns_entry *next;
13361 int priority;
13362 int weight;
13363 unsigned short port;
13364 char *host;
13365 };
13366 struct srv_dns_entry *head = NULL;
13367 struct srv_dns_entry *srv = NULL, *entry = NULL;
13368 char * s = NULL;
13369
13370 nout = 0;
13371 addr = (struct sockaddr *) malloc(sizeof(struct sockaddr));
13372 if (addr == NULL)
13373 return 0;
13374
13375 count = 1;
13376
13377 /*
13378 * First build a query of the form:
13379 *
13380 * service.protocol.host
13381 *
13382 * which will most likely be something like:
13383 *
13384 * _telnet._tcp.host
13385 *
13386 */
13387 if (((int)strlen(service) + strlen(protocol) + strlen(host) + 5)
13388 > MAX_DNS_NAMELEN
13389 )
13390 goto dnsout;
13391
13392 /* Realm names don't (normally) end with ".", but if the query
13393 doesn't end with "." and doesn't get an answer as is, the
13394 resolv code will try appending the local domain. Since the
13395 realm names are absolutes, let's stop that.
13396
13397 But only if a name has been specified. If we are performing
13398 a search on the prefix alone then the intention is to allow
13399 the local domain or domain search lists to be expanded.
13400 */
13401 h = host + strlen (host);
13402 ckmakxmsg(query, sizeof(query), "_",service,"._",protocol,".", host,
13403 ((h > host) && (h[-1] != '.')?".":NULL),
13404 NULL,NULL,NULL,NULL,NULL);
13405
13406 size = res_search(query, C_IN, T_SRV, answer.bytes, sizeof(answer.bytes));
13407
13408 if (size < hdrsize)
13409 goto dnsout;
13410
13411 /* We got a reply - See how many answers it contains. */
13412
13413 p = answer.bytes;
13414
13415 numqueries = ntohs(answer.hdr.qdcount);
13416 numanswers = ntohs(answer.hdr.ancount);
13417
13418 p += sizeof(HEADER);
13419
13420 /*
13421 * We need to skip over all of the questions, so we have to iterate
13422 * over every query record. dn_expand() is able to tell us the size
13423 * of compressed DNS names, so we use it.
13424 */
13425 while (numqueries--) {
13426 len = dn_expand(answer.bytes,answer.bytes+size,p,query,sizeof(query));
13427 if (len < 0)
13428 goto dnsout;
13429 INCR_CHECK(p, len + 4);
13430 }
13431
13432 /*
13433 * We're now pointing at the answer records. Only process them if
13434 * they're actually T_SRV records (they might be CNAME records,
13435 * for instance).
13436 *
13437 * But in a DNS reply, if you get a CNAME you always get the associated
13438 * "real" RR for that CNAME. RFC 1034, 3.6.2:
13439 *
13440 * CNAME RRs cause special action in DNS software. When a name server
13441 * fails to find a desired RR in the resource set associated with the
13442 * domain name, it checks to see if the resource set consists of a CNAME
13443 * record with a matching class. If so, the name server includes the CNAME
13444 * record in the response and restarts the query at the domain name
13445 * specified in the data field of the CNAME record. The one exception to
13446 * this rule is that queries which match the CNAME type are not restarted.
13447 *
13448 * In other words, CNAMEs do not need to be expanded by the client.
13449 */
13450 while (numanswers--) {
13451
13452 /* First is the name; use dn_expand() to get the compressed size. */
13453 len = dn_expand(answer.bytes,answer.bytes+size,p,query,sizeof(query));
13454 if (len < 0)
13455 goto dnsout;
13456 INCR_CHECK(p, len);
13457
13458 CHECK(p,2); /* Query type */
13459 type = NTOHSP(p,2);
13460
13461 CHECK(p, 6); /* Query class */
13462 class = NTOHSP(p,6); /* Also skip over 4-byte TTL */
13463
13464 CHECK(p,2); /* Record data length */
13465 rdlen = NTOHSP(p,2);
13466 /*
13467 * If this is an SRV record, process it. Record format is:
13468 *
13469 * Priority
13470 * Weight
13471 * Port
13472 * Server name
13473 */
13474 if (class == C_IN && type == T_SRV) {
13475 CHECK(p,2);
13476 priority = NTOHSP(p,2);
13477 CHECK(p, 2);
13478 weight = NTOHSP(p,2);
13479 CHECK(p, 2);
13480 port = NTOHSP(p,2);
13481 len = dn_expand(answer.
13482 bytes,
13483 answer.bytes + size,
13484 p,
13485 query,
13486 sizeof(query)
13487 );
13488 if (len < 0)
13489 goto dnsout;
13490 INCR_CHECK(p, len);
13491 /*
13492 * We got everything. Insert it into our list, but make sure
13493 * it's in the right order. Right now we don't do anything
13494 * with the weight field
13495 */
13496 srv = (struct srv_dns_entry *)malloc(sizeof(struct srv_dns_entry));
13497 if (srv == NULL)
13498 goto dnsout;
13499
13500 srv->priority = priority;
13501 srv->weight = weight;
13502 srv->port = port;
13503 makestr(&s,(char *)query); /* strdup() is not portable */
13504 srv->host = s;
13505
13506 if (head == NULL || head->priority > srv->priority) {
13507 srv->next = head;
13508 head = srv;
13509 } else
13510 /*
13511 * Confusing. Insert an entry into this spot only if:
13512 * . The next person has a higher priority (lower
13513 * priorities are preferred), or:
13514 * . There is no next entry (we're at the end)
13515 */
13516 for (entry = head; entry != NULL; entry = entry->next)
13517 if ((entry->next &&
13518 entry->next->priority > srv->priority) ||
13519 entry->next == NULL) {
13520 srv->next = entry->next;
13521 entry->next = srv;
13522 break;
13523 }
13524 } else
13525 INCR_CHECK(p, rdlen);
13526 }
13527
13528 /*
13529 * Now we've got a linked list of entries sorted by priority.
13530 * Start looking up A records and returning addresses.
13531 */
13532 if (head == NULL)
13533 goto dnsout;
13534
13535 for (entry = head; entry != NULL; entry = entry->next) {
13536 hp = gethostbyname(entry->host);
13537 if (hp != 0) {
13538
13539 /* Watch out - memset() and memcpy() are not portable... */
13540
13541 switch (hp->h_addrtype) {
13542 case AF_INET:
13543 for (j = 0; hp->h_addr_list[j]; j++) {
13544 sin = (struct sockaddr_in *) &addr[nout++];
13545 memset ((char *) sin, 0, sizeof (struct sockaddr));
13546 sin->sin_family = hp->h_addrtype;
13547 sin->sin_port = htons(entry->port);
13548 memcpy((char *) &sin->sin_addr,
13549 (char *) hp->h_addr_list[j],
13550 sizeof(struct in_addr)); /* safe */
13551 if (nout + 1 >= count) {
13552 count += 5;
13553 addr = (struct sockaddr *)
13554 realloc((char *) addr,
13555 sizeof(struct sockaddr) * count);
13556 if (!addr)
13557 goto dnsout;
13558 }
13559 }
13560 break;
13561 default:
13562 break;
13563 }
13564 }
13565 }
13566 for (entry = head; entry != NULL;) {
13567 free(entry->host);
13568 entry->host = NULL;
13569 srv = entry;
13570 entry = entry->next;
13571 free(srv);
13572 srv = NULL;
13573 }
13574
13575 dnsout:
13576 if (srv)
13577 free(srv);
13578
13579 if (nout == 0) { /* No good servers */
13580 if (addr)
13581 free(addr);
13582 return 0;
13583 }
13584 *addr_pp = addr;
13585 *naddrs = nout;
13586 return 1;
13587 }
13588 #undef INCR_CHECK
13589 #undef CHECK
13590 #undef NTOHSP
13591
13592 #define INCR_CHECK(x, y) x += y; if (x > size + answer.bytes) \
13593 return 0
13594 #define CHECK(x, y) if (x + y > size + answer.bytes) \
13595 return 0
13596 #define NTOHSP(x, y) x[0] << 8 | x[1]; x += y
13597
13598 int
locate_txt_rr(prefix,name,retstr)13599 locate_txt_rr(prefix, name, retstr)
13600 char *prefix, *name;
13601 char **retstr;
13602 {
13603 union {
13604 unsigned char bytes[2048];
13605 HEADER hdr;
13606 } answer;
13607 unsigned char *p;
13608 char host[MAX_DNS_NAMELEN], *h;
13609 int size;
13610 int type, class, numanswers, numqueries, rdlen, len;
13611
13612 /*
13613 * Form our query, and send it via DNS
13614 */
13615
13616 if (name == NULL || name[0] == '\0') {
13617 strcpy(host,prefix);
13618 } else {
13619 if ( strlen(prefix) + strlen(name) + 3 > MAX_DNS_NAMELEN )
13620 return 0;
13621
13622 /* Realm names don't (normally) end with ".", but if the query
13623 doesn't end with "." and doesn't get an answer as is, the
13624 resolv code will try appending the local domain. Since the
13625 realm names are absolutes, let's stop that.
13626
13627 But only if a name has been specified. If we are performing
13628 a search on the prefix alone then the intention is to allow
13629 the local domain or domain search lists to be expanded.
13630 */
13631 h = host + strlen (host);
13632 ckmakmsg(host,sizeof(host),prefix, ".", name,
13633 ((h > host) && (h[-1] != '.'))?".":NULL);
13634
13635 }
13636 size = res_search(host, C_IN, T_TXT, answer.bytes, sizeof(answer.bytes));
13637
13638 if (size < 0)
13639 return 0;
13640
13641 p = answer.bytes;
13642
13643 numqueries = ntohs(answer.hdr.qdcount);
13644 numanswers = ntohs(answer.hdr.ancount);
13645
13646 p += sizeof(HEADER);
13647
13648 /*
13649 * We need to skip over the questions before we can get to the answers,
13650 * which means we have to iterate over every query record. We use
13651 * dn_expand to tell us how long each compressed name is.
13652 */
13653
13654 while (numqueries--) {
13655 len = dn_expand(answer.bytes, answer.bytes + size, p, host,
13656 sizeof(host));
13657 if (len < 0)
13658 return 0;
13659 INCR_CHECK(p, len + 4); /* Name plus type plus class */
13660 }
13661
13662 /*
13663 * We're now pointing at the answer records. Process the first
13664 * TXT record we find.
13665 */
13666
13667 while (numanswers--) {
13668
13669 /* First the name; use dn_expand to get the compressed size */
13670 len = dn_expand(answer.bytes, answer.bytes + size, p,
13671 host, sizeof(host));
13672 if (len < 0)
13673 return 0;
13674 INCR_CHECK(p, len);
13675
13676 /* Next is the query type */
13677 CHECK(p, 2);
13678 type = NTOHSP(p,2);
13679
13680 /* Next is the query class; also skip over 4 byte TTL */
13681 CHECK(p,6);
13682 class = NTOHSP(p,6);
13683
13684 /* Record data length - make sure we aren't truncated */
13685
13686 CHECK(p,2);
13687 rdlen = NTOHSP(p,2);
13688
13689 if (p + rdlen > answer.bytes + size)
13690 return 0;
13691
13692 /*
13693 * If this is a TXT record, return the string. Note that the
13694 * string has a 1-byte length in the front
13695 */
13696 /* XXX What about flagging multiple TXT records as an error? */
13697
13698 if (class == C_IN && type == T_TXT) {
13699 len = *p++;
13700 if (p + len > answer.bytes + size)
13701 return 0;
13702 *retstr = malloc(len + 1);
13703 if (*retstr == NULL)
13704 return ENOMEM;
13705 strncpy(*retstr, (char *) p, len);
13706 (*retstr)[len] = '\0';
13707 /* Avoid a common error. */
13708 if ( (*retstr)[len-1] == '.' )
13709 (*retstr)[len-1] = '\0';
13710 return 1;
13711 }
13712 }
13713
13714 return 0;
13715 }
13716 #undef INCR_CHECK
13717 #undef CHECK
13718 #undef NTOHSP
13719 #endif /* CK_DNS_SRV */
13720
13721 #ifdef TNCODE
13722 #ifdef CK_FORWARD_X
13723 #ifdef UNIX
13724 #include <sys/un.h>
13725 #define FWDX_UNIX_SOCK
13726 #ifndef AF_LOCAL
13727 #define AF_LOCAL AF_UNIX
13728 #endif
13729 #ifndef PF_LOCAL
13730 #define PF_LOCAL PF_UNIX
13731 #endif
13732 #ifndef SUN_LEN
13733 /* Evaluate to actual length of the `sockaddr_un' structure. */
13734 #define SUN_LEN(ptr) ((size_t) (((struct sockaddr_un *) 0)->sun_path) \
13735 + strlen ((ptr)->sun_path))
13736 #endif
13737 #endif /* UNIX */
13738 int
fwdx_create_listen_socket(screen)13739 fwdx_create_listen_socket(screen) int screen; {
13740 #ifdef NOPUTENV
13741 return(-1);
13742 #else /* NOPUTENV */
13743 struct sockaddr_in saddr;
13744 int display, port, sock=-1, i;
13745 static char env[512];
13746
13747 /*
13748 * X Windows Servers support multiple displays by listening on
13749 * one socket per display. Display 0 is port 6000; Display 1 is
13750 * port 6001; etc.
13751 *
13752 * We start by trying to open port 6001 so that display 0 is
13753 * reserved for the local X Windows Server.
13754 */
13755
13756 for ( display=1; display < 1000 ; display++ ) {
13757
13758 if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
13759 debug(F111,"fwdx_create_listen_socket()","socket() < 0",sock);
13760 return(-1);
13761 }
13762
13763 port = 6000 + display;
13764 bzero((char *)&saddr, sizeof(saddr));
13765 saddr.sin_family = AF_INET;
13766 saddr.sin_addr.s_addr = inet_addr(myipaddr);
13767 saddr.sin_port = htons(port);
13768
13769 if (bind(sock, (struct sockaddr *)&saddr, sizeof(saddr)) < 0) {
13770 i = errno; /* Save error code */
13771 #ifdef TCPIPLIB
13772 socket_close(sock);
13773 #else /* TCPIPLIB */
13774 close(sock);
13775 #endif /* TCPIPLIB */
13776 sock = -1;
13777 debug(F110,"fwdx_create_listen_socket()","bind() < 0",0);
13778 continue;
13779 }
13780
13781 debug(F100,"fdwx_create_listen_socket() bind OK","",0);
13782 break;
13783 }
13784
13785 if ( display > 1000 ) {
13786 debug(F100,"fwdx_create_listen_socket() Out of Displays","",0);
13787 return(-1);
13788 }
13789
13790 if (listen(sock, 5) < 0) {
13791 i = errno; /* Save error code */
13792 #ifdef TCPIPLIB
13793 socket_close(sock);
13794 #else /* TCPIPLIB */
13795 close(sock);
13796 #endif /* TCPIPLIB */
13797 debug(F101,"fdwx_create_listen_socket() listen() errno","",errno);
13798 return(-1);
13799 }
13800 debug(F100,"fwdx_create_listen_socket() listen OK","",0);
13801
13802 TELOPT_SB(TELOPT_FORWARD_X).forward_x.listen_socket = sock;
13803 if (!myipaddr[0])
13804 getlocalipaddr();
13805 if ( myipaddr[0] )
13806 ckmakxmsg(env,sizeof(env),"DISPLAY=",myipaddr,":",
13807 ckuitoa(display),":",ckuitoa(screen),
13808 NULL,NULL,NULL,NULL,NULL,NULL);
13809 else
13810 ckmakmsg(env,sizeof(env),"DISPLAY=",ckuitoa(display),":",
13811 ckuitoa(screen));
13812 putenv(env);
13813 return(0);
13814 #endif /* NOPUTENV */
13815 }
13816
13817
13818 int
fwdx_open_client_channel(channel)13819 fwdx_open_client_channel(channel) int channel; {
13820 char * env;
13821 struct sockaddr_in saddr;
13822 #ifdef FWDX_UNIX_SOCK
13823 struct sockaddr_un saddr_un = { AF_LOCAL };
13824 #endif /* FWDX_UNIX_SOCK */
13825 int colon, dot, display, port, sock, i, screen;
13826 int family;
13827 char buf[256], * host=NULL, * rest=NULL;
13828 #ifdef TCP_NODELAY
13829 int on=1;
13830 #endif /* TCP_NODELAY */
13831
13832 debug(F111,"fwdx_create_client_channel()","channel",channel);
13833
13834 for ( i=0; i<MAXFWDX ; i++ ) {
13835 if (TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[i].id == channel) {
13836 /* Already open */
13837 debug(F110,"fwdx_create_client_channel()","already open",0);
13838 return(0);
13839 }
13840 }
13841
13842 env = getenv("DISPLAY");
13843 if ( !env )
13844 env = (char *)tn_get_display();
13845 if ( env )
13846 ckstrncpy(buf,env,256);
13847 else
13848 ckstrncpy(buf,"127.0.0.1:0.0",256);
13849
13850 bzero((char *)&saddr,sizeof(saddr));
13851 saddr.sin_family = AF_INET;
13852
13853 if (!fwdx_parse_displayname(buf,
13854 &family,
13855 &host,
13856 &display,
13857 &screen,
13858 &rest
13859 )
13860 ) {
13861 if ( host ) free(host);
13862 if ( rest ) free(rest);
13863 return(0);
13864 }
13865 if (rest) free(rest);
13866
13867 #ifndef FWDX_UNIX_SOCK
13868 /* if $DISPLAY indicates use of unix domain sockets, but we don't support it,
13869 * we change things to use inet sockets on the ip loopback interface instead,
13870 * and hope that it works.
13871 */
13872 if (family == FamilyLocal) {
13873 debug(F100,"fwdx_create_client_channel() FamilyLocal","",0);
13874 family = FamilyInternet;
13875 if (host) free(host);
13876 if (host = malloc(strlen("localhost") + 1))
13877 strcpy(host, "localhost");
13878 else {
13879 return(-1);
13880 }
13881 }
13882 #else /* FWDX_UNIX_SOCK */
13883 if (family == FamilyLocal) {
13884 if (host) free(host);
13885 sock = socket(PF_LOCAL, SOCK_STREAM, 0);
13886 if (sock < 0)
13887 return(-1);
13888
13889 ckmakmsg(buf,sizeof(buf),"/tmp/.X11-unix/X",ckitoa(display),NULL,NULL);
13890 strncpy(saddr_un.sun_path, buf, sizeof(saddr_un.sun_path));
13891 if (connect(sock,(struct sockaddr *)&saddr_un, SUN_LEN(&saddr_un)) < 0)
13892 return(-1);
13893 } else
13894 #endif /* FWDX_UNIX_SOCK */
13895 {
13896 /* Otherwise, we are assuming FamilyInternet */
13897 if (host) {
13898 ckstrncpy(buf,host,sizeof(buf));
13899 free(host);
13900 } else
13901 ckstrncpy(buf,myipaddr,sizeof(buf));
13902
13903 debug(F111,"fwdx_create_client_channel()","display",display);
13904
13905 port = 6000 + display;
13906 saddr.sin_port = htons(port);
13907
13908 debug(F110,"fwdx_create_client_channel() ip-address",buf,0);
13909 saddr.sin_addr.s_addr = inet_addr(buf);
13910 if ( saddr.sin_addr.s_addr == (unsigned long) -1
13911 #ifdef INADDR_NONE
13912 || saddr.sin_addr.s_addr == INADDR_NONE
13913 #endif /* INADDR_NONE */
13914 )
13915 {
13916 struct hostent *host;
13917 host = gethostbyname(buf);
13918 if ( host == NULL )
13919 return(-1);
13920 host = ck_copyhostent(host);
13921 #ifdef HADDRLIST
13922 #ifdef h_addr
13923 /* This is for trying multiple IP addresses - see <netdb.h> */
13924 if (!(host->h_addr_list))
13925 return(-1);
13926 bcopy(host->h_addr_list[0],
13927 (caddr_t)&saddr.sin_addr,
13928 host->h_length
13929 );
13930 #else
13931 bcopy(host->h_addr, (caddr_t)&saddr.sin_addr, host->h_length);
13932 #endif /* h_addr */
13933 #else /* HADDRLIST */
13934 bcopy(host->h_addr, (caddr_t)&saddr.sin_addr, host->h_length);
13935 #endif /* HADDRLIST */
13936 }
13937
13938 if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
13939 debug(F111,"fwdx_create_client_channel()","socket() < 0",sock);
13940 return(-1);
13941 }
13942
13943 if ( connect(sock, (struct sockaddr *)&saddr, sizeof(saddr)) < 0) {
13944 debug(F110,"fwdx_create_client_channel()","connect() failed",0);
13945 #ifdef TCPIPLIB
13946 socket_close(sock);
13947 #else /* TCPIPLIB */
13948 close(sock);
13949 #endif /* TCPIPLIB */
13950 return(-1);
13951 }
13952
13953 #ifdef TCP_NODELAY
13954 setsockopt(sock,IPPROTO_TCP,TCP_NODELAY,(char *)&on,sizeof(on));
13955 #endif /* TCP_NODELAY */
13956 }
13957
13958 for (i = 0; i < MAXFWDX; i++) {
13959 if (TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[i].id == -1) {
13960 TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[i].fd = sock;
13961 TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[i].id = channel;
13962 TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[i].need_to_send_xauth = 1;
13963 debug(F111,"fwdx_create_client_channel()","socket",sock);
13964 return(0);
13965 }
13966 }
13967 return(-1);
13968 }
13969
13970 int
fwdx_server_avail()13971 fwdx_server_avail() {
13972 char * env;
13973 struct sockaddr_in saddr;
13974 #ifdef FWDX_UNIX_SOCK
13975 struct sockaddr_un saddr_un = { AF_LOCAL };
13976 #endif /* FWDX_UNIX_SOCK */
13977 int colon, dot, display, port, sock, i, screen;
13978 char buf[256], *host=NULL, *rest=NULL;
13979 #ifdef TCP_NODELAY
13980 int on=1;
13981 #endif /* TCP_NODELAY */
13982 int family;
13983
13984 env = getenv("DISPLAY");
13985 if ( !env )
13986 env = (char *)tn_get_display();
13987 if ( env )
13988 ckstrncpy(buf,env,256);
13989 else
13990 ckstrncpy(buf,"127.0.0.1:0.0",256);
13991
13992 bzero((char *)&saddr,sizeof(saddr));
13993 saddr.sin_family = AF_INET;
13994
13995 if (!fwdx_parse_displayname(buf,&family,&host,&display,&screen,&rest)) {
13996 if ( host ) free(host);
13997 if ( rest ) free(rest);
13998 return(0);
13999 }
14000 if (rest) free(rest);
14001
14002 #ifndef FWDX_UNIX_SOCK
14003 /* if $DISPLAY indicates use of unix domain sockets, but we don't support it,
14004 * we change things to use inet sockets on the ip loopback interface instead,
14005 * and hope that it works.
14006 */
14007 if (family == FamilyLocal) {
14008 family = FamilyInternet;
14009 if (host) free(host);
14010 if (host = malloc(strlen("localhost") + 1))
14011 strcpy(host, "localhost");
14012 else {
14013 return(-1);
14014 }
14015 }
14016 #else /* FWDX_UNIX_SOCK */
14017 if (family == FamilyLocal) {
14018 debug(F100,"fwdx_server_avail() FamilyLocal","",0);
14019 if (host) free(host);
14020 sock = socket(PF_LOCAL, SOCK_STREAM, 0);
14021 if (sock < 0)
14022 return(0);
14023
14024 ckmakmsg(buf,sizeof(buf),"/tmp/.X11-unix/X",ckitoa(display),NULL,NULL);
14025 strncpy(saddr_un.sun_path, buf, sizeof(saddr_un.sun_path));
14026 if (connect(sock,(struct sockaddr *)&saddr_un,SUN_LEN(&saddr_un)) < 0)
14027 return(0);
14028 close(sock);
14029 return(1);
14030 }
14031 #endif /* FWDX_UNIX_SOCK */
14032
14033 /* Otherwise, we are assuming FamilyInternet */
14034 if (host) {
14035 ckstrncpy(buf,host,sizeof(buf));
14036 free(host);
14037 } else
14038 ckstrncpy(buf,myipaddr,sizeof(buf));
14039
14040 debug(F111,"fwdx_server_avail()","display",display);
14041
14042 port = 6000 + display;
14043 saddr.sin_port = htons(port);
14044
14045 debug(F110,"fwdx_server_avail() ip-address",buf,0);
14046 saddr.sin_addr.s_addr = inet_addr(buf);
14047 if ( saddr.sin_addr.s_addr == (unsigned long) -1
14048 #ifdef INADDR_NONE
14049 || saddr.sin_addr.s_addr == INADDR_NONE
14050 #endif /* INADDR_NONE */
14051 )
14052 {
14053 struct hostent *host;
14054 host = gethostbyname(buf);
14055 if ( host == NULL ) {
14056 debug(F110,"fwdx_server_avail() gethostbyname() failed",
14057 myipaddr,0);
14058 return(-1);
14059 }
14060 host = ck_copyhostent(host);
14061 #ifdef HADDRLIST
14062 #ifdef h_addr
14063 /* This is for trying multiple IP addresses - see <netdb.h> */
14064 if (!(host->h_addr_list))
14065 return(-1);
14066 bcopy(host->h_addr_list[0],
14067 (caddr_t)&saddr.sin_addr,
14068 host->h_length
14069 );
14070 #else
14071 bcopy(host->h_addr, (caddr_t)&saddr.sin_addr, host->h_length);
14072 #endif /* h_addr */
14073 #else /* HADDRLIST */
14074 bcopy(host->h_addr, (caddr_t)&saddr.sin_addr, host->h_length);
14075 #endif /* HADDRLIST */
14076 }
14077
14078 if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
14079 debug(F111,"fwdx_server_avail()","socket() < 0",sock);
14080 return(0);
14081 }
14082
14083 if ( connect(sock, (struct sockaddr *)&saddr, sizeof(saddr)) < 0) {
14084 debug(F110,"fwdx_server_avail()","connect() failed",0);
14085 #ifdef TCPIPLIB
14086 socket_close(sock);
14087 #else /* TCPIPLIB */
14088 close(sock);
14089 #endif /* TCPIPLIB */
14090 return(0);
14091 }
14092
14093 #ifdef TCPIPLIB
14094 socket_close(sock);
14095 #else /* TCPIPLIB */
14096 close(sock);
14097 #endif /* TCPIPLIB */
14098 return(1);
14099 }
14100
14101 int
fwdx_open_server_channel()14102 fwdx_open_server_channel() {
14103 int sock, ready_to_accept, sock2,channel,i;
14104 #ifdef TCP_NODELAY
14105 int on=1;
14106 #endif /* TCP_NODELAY */
14107 #ifdef UCX50
14108 static u_int saddrlen;
14109 #else
14110 static SOCKOPT_T saddrlen;
14111 #endif /* UCX50 */
14112 struct sockaddr_in saddr;
14113 char sb[8];
14114 extern char tn_msg[];
14115 #ifdef BSDSELECT
14116 fd_set rfds;
14117 struct timeval tv;
14118 #else
14119 #ifdef BELLSELCT
14120 fd_set rfds;
14121 #else
14122 fd_set rfds;
14123 struct timeval {
14124 long tv_sec;
14125 long tv_usec;
14126 } tv;
14127 #endif /* BELLSELECT */
14128 #endif /* BSDSELECT */
14129 unsigned short nchannel;
14130 unsigned char * p;
14131
14132 sock = TELOPT_SB(TELOPT_FORWARD_X).forward_x.listen_socket;
14133
14134 try_again:
14135
14136 #ifdef BSDSELECT
14137 tv.tv_sec = tv.tv_usec = 0L;
14138 tv.tv_usec = 50;
14139 FD_ZERO(&rfds);
14140 FD_SET(sock, &rfds);
14141 ready_to_accept =
14142 ((select(FD_SETSIZE,
14143 #ifdef HPUX
14144 #ifdef HPUX1010
14145 (fd_set *)
14146 #else
14147
14148 (int *)
14149 #endif /* HPUX1010 */
14150 #else
14151 #ifdef __DECC
14152 (fd_set *)
14153 #endif /* __DECC */
14154 #endif /* HPUX */
14155 &rfds, NULL, NULL, &tv) > 0) &&
14156 FD_ISSET(sock, &rfds));
14157 #else /* BSDSELECT */
14158 #ifdef IBMSELECT
14159 ready_to_accept = (select(&sock, 1, 0, 0, 50) == 1);
14160 #else
14161 #ifdef BELLSELECT
14162 FD_ZERO(rfds);
14163 FD_SET(sock, rfds);
14164 ready_to_accept =
14165 ((select(128, rfds, NULL, NULL, 50) > 0) &&
14166 FD_ISSET(sock, rfds));
14167 #else
14168 /* Try this - what's the worst that can happen... */
14169
14170 tv.tv_sec = tv.tv_usec = 0L;
14171 tv.tv_usec = 50;
14172 FD_ZERO(&rfds);
14173 FD_SET(sock, &rfds);
14174 ready_to_accept =
14175 ((select(FD_SETSIZE,
14176 (fd_set *) &rfds, NULL, NULL, &tv) > 0) &&
14177 FD_ISSET(sock, &rfds));
14178 #endif /* BELLSELECT */
14179 #endif /* IBMSELECT */
14180 #endif /* BSDSELECT */
14181
14182 if ( !ready_to_accept )
14183 return(0);
14184
14185 if ((sock2 = accept(sock,(struct sockaddr *)&saddr,&saddrlen)) < 0) {
14186 int i = errno; /* save error code */
14187 debug(F101,"tcpsrv_open accept errno","",i);
14188 return(-1);
14189 }
14190
14191 /*
14192 * Now we have the open socket. We must now find a channel to store
14193 * it in, and then notify the client.
14194 */
14195
14196 for ( channel=0;channel<MAXFWDX;channel++ ) {
14197 if ( TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[channel].fd == -1 )
14198 break;
14199 }
14200
14201 if ( channel == MAXFWDX ) {
14202 #ifdef TCPIPLIB
14203 socket_close(sock2);
14204 #else /* TCPIPLIB */
14205 close(sock2);
14206 #endif /* TCPIPLIB */
14207 return(-1);
14208 }
14209
14210 if ( fwdx_send_open(channel) < 0 ) {
14211 #ifdef TCPIPLIB
14212 socket_close(sock2);
14213 #else /* TCPIPLIB */
14214 close(sock2);
14215 #endif /* TCPIPLIB */
14216 }
14217
14218 #ifdef TCP_NODELAY
14219 setsockopt(sock2,IPPROTO_TCP,TCP_NODELAY,(char *)&on,sizeof(on));
14220 #endif /* TCP_NODELAY */
14221
14222 TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[channel].fd = sock2;
14223 TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[channel].id = channel;
14224 goto try_again;
14225
14226 return(0); /* never reached */
14227 }
14228
14229 int
fwdx_close_channel(channel)14230 fwdx_close_channel(channel) int channel; {
14231 int i,fd;
14232
14233 for ( i=0; i<MAXFWDX ; i++ ) {
14234 if (TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[i].id == channel)
14235 break;
14236 }
14237 if ( i == MAXFWDX )
14238 return(-1);
14239
14240 fd = TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[i].fd;
14241 TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[i].fd = -1;
14242 TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[i].id = -1;
14243 TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[i].need_to_send_xauth = 0;
14244
14245 #ifdef TCPIPLIB
14246 socket_close(fd);
14247 #else /* TCPIPLIB */
14248 close(fd);
14249 #endif /* TCPIPLIB */
14250 return(0);
14251 }
14252
14253 int
fwdx_close_all()14254 fwdx_close_all() {
14255 int x,fd;
14256
14257 debug(F111,"fwdx_close_all()",
14258 "TELOPT_SB(TELOPT_FORWARD_X).forward_x.listen_socket",
14259 TELOPT_SB(TELOPT_FORWARD_X).forward_x.listen_socket);
14260
14261 if ( TELOPT_SB(TELOPT_FORWARD_X).forward_x.listen_socket != -1 ) {
14262 #ifdef TCPIPLIB
14263 socket_close(TELOPT_SB(TELOPT_FORWARD_X).forward_x.listen_socket);
14264 #else /* TCPIPLIB */
14265 close(TELOPT_SB(TELOPT_FORWARD_X).forward_x.listen_socket);
14266 #endif /* TCPIPLIB */
14267 TELOPT_SB(TELOPT_FORWARD_X).forward_x.listen_socket = -1;
14268 }
14269
14270 for (x = 0; x < MAXFWDX; x++) {
14271 if (TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].fd != -1) {
14272 fd = TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].fd;
14273 TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].fd = -1;
14274 TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].id = -1;
14275 TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].need_to_send_xauth = 0;
14276 TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].suspend = 0;
14277 #ifdef TCPIPLIB
14278 socket_close(fd);
14279 #else /* TCPIPLIB */
14280 close(fd);
14281 #endif /* TCPIPLIB */
14282 }
14283 }
14284 return(0);
14285 }
14286
14287 /* The following definitions are for Unix */
14288 #ifndef socket_write
14289 #define socket_write(f,s,n) write(f,s,n)
14290 #endif /* socket_write */
14291 #ifndef socket_read
14292 #define socket_read(f,s,n) read(f,s,n)
14293 #endif /* socket_read */
14294
14295 int
fwdx_write_data_to_channel(channel,data,len)14296 fwdx_write_data_to_channel(channel, data, len)
14297 int channel; char * data; int len;
14298 {
14299 int sock, count, try=0, length = len, i;
14300
14301 if ( len <= 0 )
14302 return(0);
14303
14304 for ( i=0; i<MAXFWDX ; i++ ) {
14305 if (TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[i].id == channel)
14306 break;
14307 }
14308 if ( i == MAXFWDX ) {
14309 debug(F110,"fwdx_write_data_to_channel",
14310 "attempting to write to closed channel",0);
14311 return(-1);
14312 }
14313
14314 sock = TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[i].fd;
14315 debug(F111,"fwdx_write_data_to_channel","socket",sock);
14316 ckhexdump("fwdx_write_data_to_channel",data,len);
14317
14318 fwdx_write_data_to_channel_retry:
14319
14320 if ((count = socket_write(sock,data,len)) < 0) {
14321 int s_errno = socket_errno; /* maybe a function */
14322 debug(F101,"fwdx_write_data_to_channel socket_write error","",s_errno);
14323 #ifdef BETATEST
14324 printf("fwdx_write_data_to_channel error\r\n");
14325 #endif /* BETATEST */
14326 #ifdef OS2
14327 if (os2socketerror(s_errno) < 0)
14328 return(-2);
14329 #endif /* OS2 */
14330 return(-1); /* Call it an i/o error */
14331 }
14332 if (count < len) {
14333 debug(F111,"fwdx_write_data_to_channel socket_write",data,count);
14334 if (count > 0) {
14335 data += count;
14336 len -= count;
14337 }
14338 debug(F111,"fwdx_write_data_to_channel retry",data,len);
14339 if ( len > 0 )
14340 goto fwdx_write_data_to_channel_retry;
14341 }
14342
14343 debug(F111,"fwdx_write_data_to_channel complete",data,length);
14344 return(length); /* success - return total length */
14345 }
14346
14347 VOID
fwdx_check_sockets(fd_set * ibits)14348 fwdx_check_sockets(fd_set *ibits)
14349 {
14350 int x, sock, channel, bytes;
14351 static char buffer[32000];
14352
14353 debug(F100,"fwdx_check_sockets()","",0);
14354 if ( sstelnet && !TELOPT_ME(TELOPT_FORWARD_X) ||
14355 !sstelnet && !TELOPT_U(TELOPT_FORWARD_X)) {
14356 debug(F110,"fwdx_check_sockets()","TELOPT_FORWARD_X not negotiated",0);
14357 return;
14358 }
14359
14360 for (x = 0; x < MAXFWDX; x++) {
14361 if ( TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].fd == -1 ||
14362 TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].suspend )
14363 continue;
14364
14365 sock = TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].fd;
14366 if (FD_ISSET(sock, ibits))
14367 {
14368 channel = TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].id;
14369 debug(F111,"fwdx_check_sockets()","channel set",channel);
14370
14371 bytes = socket_read(sock, buffer, sizeof(buffer));
14372 if (bytes > 0)
14373 fwdx_send_data_from_channel(channel, buffer, bytes);
14374 else if (bytes == 0) {
14375 fwdx_close_channel(channel);
14376 fwdx_send_close(channel);
14377 }
14378 }
14379 }
14380 }
14381
14382 int
fwdx_init_fd_set(fd_set * ibits)14383 fwdx_init_fd_set(fd_set *ibits)
14384 {
14385 int x,set=0,cnt=0;
14386
14387 if ( sstelnet && !TELOPT_ME(TELOPT_FORWARD_X) ||
14388 !sstelnet && !TELOPT_U(TELOPT_FORWARD_X)) {
14389 debug(F110,"fwdx_init_fd_set()","TELOPT_FORWARD_X not negotiated",0);
14390 return(0);
14391 }
14392
14393 if (TELOPT_SB(TELOPT_FORWARD_X).forward_x.listen_socket != -1) {
14394 set++;
14395 FD_SET(TELOPT_SB(TELOPT_FORWARD_X).forward_x.listen_socket, ibits);
14396 }
14397 for (x = 0; x < MAXFWDX; x++) {
14398 if (TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].fd != -1) {
14399 cnt++;
14400 if (TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].suspend)
14401 continue;
14402 set++;
14403 FD_SET(TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].fd, ibits);
14404 }
14405 }
14406 if (set + cnt == 0) {
14407 return(-1);
14408 } else {
14409 return(set);
14410 }
14411 }
14412
14413 #ifdef NT
14414 VOID
fwdx_thread(VOID * dummy)14415 fwdx_thread( VOID * dummy )
14416 {
14417 fd_set ifds;
14418 struct timeval tv;
14419 extern int priority;
14420 int n;
14421
14422 setint();
14423 SetThreadPrty(priority,isWin95() ? 3 : 11);
14424
14425 while ( !sstelnet && TELOPT_U(TELOPT_FORWARD_X) ||
14426 sstelnet && TELOPT_ME(TELOPT_FORWARD_X))
14427 {
14428 FD_ZERO(&ifds);
14429 n = fwdx_init_fd_set(&ifds);
14430 if (n > 0) {
14431 tv.tv_sec = 0;
14432 tv.tv_usec = 2500;
14433 if ( select(FD_SETSIZE, &ifds, NULL, NULL, &tv) > 0 )
14434 fwdx_check_sockets(&ifds);
14435
14436 } else if (n < 0) {
14437 TELOPT_SB(TELOPT_FORWARD_X).forward_x.thread_started = 0;
14438 ckThreadEnd(NULL);
14439 } else {
14440 sleep(1);
14441 }
14442 }
14443 }
14444 #endif /* NT */
14445 #endif /* CK_FORWARD_X */
14446 #endif /* TNCODE */
14447 #endif /* NETCONN */
14448