1: char *cknetv = "Network support, 5A(015) 23 Nov 92";
   2: 
   3: /*  C K C N E T  --  Network support  */
   4: /*
   5:   Authors:
   6: 
   7:   Frank da Cruz (fdc@columbia.edu, FDCCU@CUVMA.BITNET),
   8:     Columbia University Center for Computing Activities.
   9:   netopen() routine for TCP/IP originally by Ken Yap, Rochester University
  10:     (ken@cs.rochester.edu) (no longer at that address).
  11:   Missing pieces for Excelan sockets library from William Bader, Moravian
  12:     College <bader@moravian.edu>.
  13:   TELNET protocol by Frank da Cruz.
  14:   TGV MultiNet code by Frank da Cruz.
  15:   MultiNet code adapted to WIN/TCP by Ray Hunter of TWG.
  16:   MultiNet code adapted to DEC TCP/IP by Lee Tibbert of DEC and Frank da Cruz.
  17:   SunLink X.25 support by Marcello Frutig, Catholic University,
  18:     Rio de Janeiro, Brazil (frutig@rnp.impa.br) with fixes from
  19:     Stefaan Eeckels, Eurokom, Luxembourg.
  20:   Other contributions as indicated below.
  21: 
  22:   Copyright (C) 1985, 1992, Trustees of Columbia University in the City of New
  23:   York.  Permission is granted to any individual or institution to use this
  24:   software as long as it is not sold for profit.  This copyright notice must be
  25:   retained.  This software may not be included in commercial products without
  26:   written permission of Columbia University.
  27: */
  28: 
  29: #include "ckcdeb.h"
  30: #include "ckcker.h"
  31: #ifdef I386IX               /* Has to come before ckcnet.h in */
  32: #include <errno.h>          /* this version, but after in others */
  33: #endif /* I386IX */
  34: #include "ckcnet.h"
  35: 
  36: #ifdef NETCONN
  37: /* Don't need these if there is no network support. */
  38: 
  39: #ifdef WINTCP
  40: 
  41: #include <errno.h>
  42: #include <setjmp.h>
  43: #include <signal.h>
  44: /*
  45:  * The WIN/TCP code path is the same as that for Multinet.  Only the routine
  46:  * names have changed ...
  47:  */
  48: #define socket_errno    errno
  49: #define socket_read     netread
  50: #define socket_ioctl    ioctl
  51: #define socket_write    netwrite
  52: #define socket_perror   win$perror
  53: #define socket_close    netclose
  54: 
  55: #else /* Not WINTCP */
  56: #ifndef I386IX
  57: #include <errno.h>
  58: #endif /* I386IX */
  59: #include <signal.h>
  60: #ifndef ZILOG
  61: #include <setjmp.h>
  62: #else
  63: #include <setret.h>
  64: #endif /* ZILOG */
  65: #endif /* WINTCP */
  66: 
  67: #ifdef datageneral          /* Data General AOS/VS */
  68: #include <:usr:include:vs_tcp_errno.h>
  69: #include <:usr:include:sys:vs_tcp_types.h>
  70: #include <:usr:include:sys:socket.h>
  71: #include <:usr:include:netinet:in.h>
  72: #include <:usr:include:netdb.h>
  73: #endif /* datageneral */
  74: 
  75: extern SIGTYP (*saval)();       /* For saving alarm handler */
  76: 
  77: _PROTOTYP( VOID bgchk, (void) );
  78: 
  79: extern int              /* External variables */
  80:   duplex, debses, seslog, ttyfd, quiet, msgflg;
  81: 
  82: #ifdef SVR4
  83: /*
  84:   These suggested by Rob Healey, rhealey@kas.helios.mn.org, to avoid
  85:   bugs in Berkeley compatibility library on Sys V R4 systems, but untested
  86:   by me (fdc).  Remove this bit if it gives you trouble.
  87:   (Later corrected by Marc Boucher <mboucher@iro.umontreal.ca> because
  88:   bzero/bcopy are not argument-compatible with memset/memcpy|memmove.)
  89: */
  90: #define bzero(s,n) memset(s,0,n)
  91: #define bcopy(h,a,l) memmove(a,h,l)
  92: #else
  93: #ifdef PTX              /* Sequent DYNIX PTX 1.3 */
  94: #define bzero(s,n) memset(s,0,n)
  95: #define bcopy(h,a,l) memcpy(a,h,l)
  96: #endif /* PTX */
  97: #endif /* SVR4 */
  98: 
  99: #define NAMECPYL 100            /* Local copy of hostname */
 100: static char namecopy[NAMECPYL];
 101: 
 102: char ipaddr[20] = { '\0' };     /* Global copy of IP address */
 103: 
 104: /*
 105:   VMSTCPIP means "DEC_TCPIP or MULTINET or WINTCP" (defined in ckcnet.h).
 106: */
 107: #ifdef VMSTCPIP
 108: /*
 109:   General global variables, but so far used only by MultiNet and WIN/TCP.
 110:   Kept within #ifdef MULTINET..#endif to keep strict compilers (and lint)
 111:   from complaining about unused variables.
 112: */
 113: static jmp_buf njbuf;           /* For timeout longjumps */
 114: #endif /* VMSTCPIP */
 115: 
 116: #endif /* NETCONN */
 117: 
 118: int ttnet = NET_NONE;           /* Network type */
 119: int ttnproto = NP_NONE;         /* Network virtual terminal protocol */
 120: int tn_init = 0;            /* Telnet protocol initialized flag */
 121: int tn_duplex = 1;          /* Initial echo status */
 122: char *tn_term = NULL;           /* Terminal type override */
 123: int tn_nlm = 1;             /* Telnet CR -> CR LF mode */
 124: 
 125: #ifndef NETCONN
 126: /*
 127:   Network support not defined.
 128:   Dummy functions here in case #ifdef's forgotten elsewhere.
 129: */
 130: int                 /* Open network connection */
 131: netopen(name, lcl, nett) char *name; int *lcl, nett; {
 132:     return(-1);
 133: }
 134: int                 /* Close network connection */
 135: netclos() {
 136:     return(-1);
 137: }
 138: int                 /* Check network input buffer */
 139: nettchk() {
 140:     return(-1);
 141: }
 142: int                 /* Flush network input buffer */
 143: netflui() {
 144:     return(-1);
 145: }
 146: int                 /* Send network BREAK */
 147: netbreak() {
 148:     return(-1);
 149: }
 150: int                 /* Input character from network */
 151: netinc(timo) int timo; {
 152: }
 153: int                 /* Output character to network */
 154: #ifdef CK_ANSIC
 155: nettoc(char c)
 156: #else
 157: nettoc(c) char c;
 158: #endif /* CK_ANSIC */
 159: /* nettoc */ {
 160:     return(-1);
 161: }
 162: int
 163: nettol(s,n) char *s; int n; {
 164:     return(-1);
 165: }
 166: 
 167: #else /* NETCONN is defined (rest of this module...) */
 168: 
 169: #ifdef VMSTCPIP
 170: 
 171: /* For buffered network reads... */
 172: /*
 173:   If the buffering code is written right, it shouldn't matter how long this
 174:   buffer is -- it could even be shorter than a Kermit packet.
 175: */
 176: #define TTIBUFL 8192            /* Maybe 8K?... */
 177: 
 178: CHAR    ttibuf[TTIBUFL+1];
 179: int     ttibp = 0, ttibn = 0;
 180: /*
 181:   Read bytes from network into internal buffer ttibuf[].
 182:   To be called when input buffer is empty, i.e. when ttibn == 0.
 183: 
 184:   Other network reading routines, like ttinc, ttinl, ttxin, should check the
 185:   internal buffer first, and call this routine for a refill if necessary.
 186: 
 187:   Returns -1 on error, 0 if nothing happens.  When data is read successfully,
 188:   returns number of bytes read, and sets global ttibn to that number and
 189:   ttibp (the buffer pointer) to zero.
 190: */
 191: int
 192: ttbufr() {              /* TT Buffer Read */
 193:     int count;
 194: 
 195:     if (ttnet != NET_TCPB) {        /* First make sure current net is */
 196:     return(-1);         /* TCP/IP; if not, do nothing. */
 197:     } else {
 198:     if (ttibn > 0)          /* Out internal buffer is not empty, */
 199:       return(ttibn);        /* so keep using it. */
 200: #ifdef WINTCP
 201:     count = 512;            /* This works for WIN/TCP */
 202: #else                   /* Not WINTCP, i.e it's Multinet */
 203: #ifdef DEC_TCPIP
 204:     count = 512;            /* This works for WIN/TCP */
 205: #else                   /* Not WINTCP, i.e it's Multinet */
 206:     count = nettchk();      /* Check network input buffer, */
 207:     if (ttibn > 0) return(ttibn);   /* which can put a char there! */
 208:     if (count < 0)          /* Read error */
 209:       return(-1);
 210:     else if (count > TTIBUFL)   /* Too many to read */
 211:       count = TTIBUFL;
 212:     else if (count == 0)        /* None, so force blocking read */
 213:       count = 1;
 214: #endif /* DEC_TCPIP */
 215: #endif /* WINTCP */
 216:     debug(F101,"ttbufr count 1","",count);
 217: 
 218: #ifdef COMMENT
 219: /*
 220:  This is for nonblocking reads, which we don't do any more.  This code didn't
 221:  work anyway, in the sense that a broken connection was never sensed.
 222: */
 223:     if ((count = socket_read(ttyfd,ttibuf,count)) < 1) {
 224:         if (count == -1 && socket_errno == EWOULDBLOCK) {
 225:         debug(F100,"ttbufr finds nothing","",0);
 226:         return(0);
 227:         } else if (count == 0) {
 228:         debug(F100,"ttbufr socket eof","",0);
 229:         return(-1);
 230:         } else {
 231:         debug(F101,"ttbufr socket_read error","",socket_errno);
 232:         return(-1);
 233:         }
 234:     }
 235: #else
 236: /* This is for blocking reads */
 237:     if ((count = socket_read(ttyfd,ttibuf,count)) < 1) {
 238:         debug(F101,"ttbufr socket_read","",count);
 239:         debug(F101,"ttbufr socket_errno","",socket_errno);
 240:         return(-1);
 241:     }
 242: #endif /* COMMENT */
 243:     ttibp = 0;          /* Reset buffer pointer. */
 244:     ttibn = count;
 245: #ifdef DEBUG
 246:     debug(F101,"ttbufr count 2","",count); /* Got some bytes. */
 247:     if (count > 0) ttibuf[count] = '\0';
 248:     debug(F111,"ttbufr ttibuf",ttibuf,ttibp);
 249: #endif /* DEBUG */
 250:     return(ttibn);          /* Return buffer count. */
 251:     }
 252: }
 253: #endif /* VMSTCPIP */
 254: 
 255: /*
 256:   C-Kermit network open/close functions for BSD-sockets.
 257:   Much of this code shared by SunLink X.25, which also uses the socket library.
 258: */
 259: 
 260: /*  N E T O P E N  --  Open a network connection.  */
 261: 
 262: /*  Returns 0 on success, -1 on failure.  */
 263: 
 264: #define TELNET_PORT 23     /* Should do lookup, but it won't change */
 265: 
 266: /* This symbol is not known to, e.g., Ultrix 2.0 */
 267: #ifndef TELOPT_TTYPE
 268: #define TELOPT_TTYPE 24
 269: #endif /* TELOPT_TTYPE */
 270: 
 271: /*  N E T O P N  --  Open a network connection.  */
 272: /*
 273:   Call with:
 274:     name of host (or host:service),
 275:     lcl - local-mode flag to be set if this function succeeds,
 276:     network type - value defined in ckunet.h.
 277: */
 278: 
 279: #ifdef EXCELAN
 280: /*
 281:   Most other BSD sockets implementations define these in header files
 282:   and libraries.
 283: */
 284: struct servent {
 285:     unsigned short s_port;
 286: };
 287: 
 288: struct hostent {
 289:     short h_addrtype;
 290:     struct in_addr h_addr;
 291:     int h_length;
 292: };
 293: 
 294: struct servent *
 295: getservbyname(service, connection) char *service,*connection; {
 296:     static struct servent servrec;
 297:     int port;
 298: 
 299:     port = 0;
 300:     if (strcmp(service, "telnet") == 0) port = 23;
 301:     else if (strcmp(service, "smtp") == 0) port = 25;
 302:     else port = atoi(service);
 303: 
 304:     debug(F101,"getservbyname return port ","",port);
 305: 
 306:     if (port > 0) {
 307:         servrec.s_port = htons(port);
 308:         return( &servrec );
 309:     }
 310:     return( (struct servent *) NULL );
 311: }
 312: 
 313: struct hostent *
 314: gethostbyname(hostname) char *hostname; {
 315:     return( (struct hostent *) NULL );
 316: }
 317: 
 318: unsigned long
 319: inet_addr(name) char *name; {
 320:     unsigned long addr;
 321: 
 322:     addr = rhost(&name);
 323:     debug(F111,"inet_addr ",name,(int)addr);
 324:     return(addr);
 325: }
 326: 
 327: char *
 328: inet_ntoa(in) struct in_addr in; {
 329:     static char name[80];
 330:     sprintf(name, "%d.%d.%d.%d", in.s_net, in.s_host, in.s_lh, in.s_impno);
 331:     return(name);
 332: }
 333: #endif /* EXCELAN */
 334: 
 335: /*  N E T O P E N  --  Open a network connection  */
 336: /*
 337:   Calling conventions same as ttopen(), except third argument is network
 338:   type rather than modem type.  Designed to be called from within ttopen.
 339: */
 340: int
 341: netopen(name, lcl, nett) char *name; int *lcl, nett; {
 342:     char *p;
 343: #ifdef SO_OOBINLINE
 344:     int on = 1;
 345: #endif /* SO_OOBINLINE */
 346:     int i, x;
 347:     struct servent *service, servrec;
 348:     struct hostent *host;
 349:     struct sockaddr_in saddr;
 350: #ifdef EXCELAN
 351:     struct sockaddr_in send_socket;
 352: #endif /* EXCELAN */
 353: 
 354: #ifdef SUNX25               /* Code for SunLink X.25 support */
 355: #define X29PID 1            /* X.29 Protocol ID */
 356:     VOID x25oobh();
 357:     CONN_DB x25host;
 358:     FACILITY_DB x25facil;
 359:     static int needh = 1;
 360:     PID_T pid;
 361:     extern int linkid, lcn, x25ver;
 362:     extern int revcall, closgr, cudata;
 363:     extern char udata[MAXCUDATA];
 364: #endif /* SUNX25 */
 365: 
 366:     debug(F101,"netopen nett","",nett);
 367:     *ipaddr = '\0';         /* Initialize IP address string */
 368: 
 369: #ifdef SUNX25
 370:     if (nett == NET_SX25) {     /* If network type is X.25 */
 371:         netclos();          /* Close any previous net connection */
 372:         ttnproto = NP_NONE;     /* No protocol selected yet */
 373: 
 374:         /* Set up host structure */
 375:         bzero ((char *)&x25host,sizeof(x25host));
 376:         if ((x25host.hostlen = pkx121 (name,x25host.host)) < 0) {
 377:             fprintf (stderr,"Invalid X.121 host address %s\n",name);
 378:             errno = 0;
 379:             return (-1);
 380:         }
 381:         x25host.datalen = X29PIDLEN;
 382:         x25host.data[0] = X29PID;
 383: 
 384:     /* Set call user data if specified */
 385:         if (cudata) {
 386:             strncpy(x25host.data+X29PIDLEN,udata,(int)strlen(udata));
 387:             x25host.datalen += (int)strlen(udata);
 388:         }
 389: 
 390:         /* Open SunLink X.25 socket */
 391:         if ((ttyfd = socket (AF_X25, SOCK_STREAM, 0)) < 0) {
 392:         debug(F101,"netopen socket error","",errno);
 393:             perror ("X.25 connect socket error");
 394:             return (-1);
 395:         }
 396: 
 397:         /* Setting X.25 out-of-band data handler */
 398:         pid = getpid();
 399:         if (ioctl(ttyfd,SIOCSPGRP,&pid)) {
 400:             perror("Setting process group id");
 401:             return(-1);
 402:         }
 403:         (VOID) signal(SIGURG,x25oobh);
 404: 
 405:         /* Set reverse charge call and closed user group if requested */
 406:         bzero ((char *)&x25facil,sizeof(x25facil));
 407:         if (revcall) x25facil.reverse_charge = revcall;
 408:         if (closgr > -1) {
 409:             x25facil.cug_req = 1;
 410:             x25facil.cug_index = closgr;
 411:         }
 412:         if (ioctl(ttyfd,X25_WR_FACILITY,&x25facil) < 0) {
 413:             perror ("Setting X.25 facilities");
 414:             return (-1);
 415:         }
 416: 
 417:         /*  Need X.25 header with bits Q and M */
 418:         if (ioctl (ttyfd,X25_HEADER,&needh) < 0) {
 419:             perror ("Setting X.25 header");
 420:             return (-1);
 421:         }
 422: 
 423:         /* Connects to remote host via SunLink X.25 */
 424:         if (connect(ttyfd,&x25host,sizeof(x25host)) < 0) {
 425:             debug(F101,"netopen connect errno","",errno);
 426:             i = errno;
 427:         if (errno) {
 428:                 perror("netopen");
 429:                 x25diag();
 430:             }
 431:             (VOID) close (ttyfd);
 432:             ttyfd = -1;
 433:             errno = i;
 434:             return (-1);
 435:         }
 436: 
 437:         /* Get X.25 link identification used for the connection */
 438:         if (ioctl(ttyfd,X25_GET_LINK,&linkid) < 0) {
 439:             perror ("Getting X.25 link id");
 440:             return (-1);
 441:         }
 442: 
 443:         /* Get X.25 logical channel number used for the connection */
 444:         if (ioctl(ttyfd,X25_RD_LCGN,&lcn) < 0) {
 445:             perror ("Getting X.25 lcn");
 446:             return (-1);
 447:         }
 448: 
 449:         /* Get SunLink X.25 version */
 450:         if (ioctl(ttyfd,X25_VERSION,&x25ver) < 0) {
 451:             perror ("Getting SunLink X.25 version");
 452:             return (-1);
 453:         }
 454:         ttnet = nett;                   /* Sunlink X.25 network */
 455:         ttnproto = NP_X3;               /* PAD X.3, X.28, X.29 protocol */
 456:         if (*lcl < 0) *lcl = 1;         /* Local mode */
 457:         return(0);
 458:     } else /* Note that SUNX25 support can coexist with TCP/IP support. */
 459: #endif /* SUNX25 */
 460: /*
 461:   Add support for other networks here.
 462: */
 463:     if (nett != NET_TCPB) return(-1);   /* BSD socket support */
 464: 
 465:     netclos();              /* Close any previous connection. */
 466:     strncpy(namecopy, name, NAMECPYL);  /* Copy the hostname. */
 467:     ttnproto = NP_NONE;         /* No protocol selected yet. */
 468:     debug(F110,"netopen namecopy",namecopy,0);
 469: 
 470:     p = namecopy;           /* Was a service requested? */
 471:     while (*p != '\0' && *p != ':') p++; /* Look for colon */
 472:     if (*p == ':') {            /* Have a colon */
 473:     *p++ = '\0';            /* Get service name or number */
 474:     } else {                /* Otherwise use telnet */
 475:     p = "telnet";
 476:     }
 477:     debug(F110,"netopen service requested",p,0);
 478:     if (isdigit(*p)) {          /* Use socket number without lookup */
 479:     service = &servrec;
 480:     service->s_port = htons((unsigned short)atoi(p));
 481:     } else {                /* Otherwise lookup the service name */
 482:     service = getservbyname(p, "tcp");
 483:     }
 484:     if (!service) {
 485:     fprintf(stderr, "Cannot find port for service %s\n", p);
 486: #ifdef MULTINET
 487:     debug(F101,"netopen can't get service","",socket_errno);
 488: #else
 489:     debug(F101,"netopen can't get service","",errno);
 490: #endif /* MULTINET */
 491:     errno = 0;          /* rather than mislead */
 492:     return(-1);
 493:     }
 494:     /* Set up socket structure and get host address */
 495: 
 496:     bzero((char *)&saddr, sizeof(saddr));
 497:     if ((host = gethostbyname(namecopy)) != NULL) {
 498:     saddr.sin_family = host->h_addrtype;
 499:     bcopy(host->h_addr, (caddr_t)&saddr.sin_addr, host->h_length);
 500:     } else {
 501: #ifdef INADDRX
 502: /* inet_addr() is of type struct in_addr */
 503:     struct in_addr ina;
 504:     unsigned long uu;
 505: #ifdef datageneral
 506:         extern struct in_addr inet_addr();
 507: #endif /* datageneral */
 508:     ina = inet_addr(namecopy);
 509:     uu = *(unsigned long *)&ina;
 510: #else /* Not INADDRX */
 511: /* inet_addr() is unsigned long */
 512:     unsigned long uu;
 513:     uu = inet_addr(namecopy);
 514: #endif /* INADDRX */
 515:     if ((saddr.sin_addr.s_addr = uu) != ((unsigned long)-1))
 516:       saddr.sin_family = AF_INET;
 517:     else {
 518:       fprintf(stderr, "Can't get address for %s\n", namecopy);
 519: #ifdef MULTINET
 520:       debug(F101,"netopen can't get address","",socket_errno);
 521: #else
 522:       debug(F101,"netopen can't get address","",errno);
 523: #endif /* MULTINET */
 524:       errno = 0;            /* rather than mislead */
 525:       return(-1);
 526:       }
 527:     }
 528: 
 529:     /* Get a file descriptor for the connection. */
 530: 
 531:     saddr.sin_port = service->s_port;
 532:     sprintf(ipaddr,"%s", inet_ntoa(saddr.sin_addr));
 533:     if (!quiet && *ipaddr) printf(" Trying %s...\n", ipaddr);
 534: 
 535: #ifdef EXCELAN
 536:     send_socket.sin_family = AF_INET;
 537:     send_socket.sin_addr.s_addr = 0;
 538:     send_socket.sin_port = 0;
 539:     if ((ttyfd = socket(SOCK_STREAM, (struct sockproto *)0,
 540:         &send_socket, SO_REUSEADDR)) < 0)
 541: #else
 542:     if ((ttyfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
 543: #endif /* EXCELAN */
 544:       {
 545: #ifdef EXCELAN
 546:     experror("TCP socket error");
 547: #else
 548: #ifdef MULTINET
 549:     socket_perror("TCP socket error");
 550:     debug(F101,"netopen socket error","",socket_errno);
 551: #else
 552:     perror("TCP socket error");
 553:     debug(F101,"netopen socket error","",errno);
 554: #endif /* MULTINET */
 555: #endif /* EXCELAN */
 556:     return (-1);
 557:     }
 558:     errno = 0;
 559: 
 560:     /* Now connect to the socket on the other end. */
 561: 
 562: #ifdef EXCELAN
 563:     if (connect(ttyfd, &saddr) < 0)
 564: #else
 565:     if (connect(ttyfd, (struct sockaddr *)&saddr, sizeof(saddr)) < 0)
 566: #endif /* EXCELAN */
 567:       {
 568:     i = errno;          /* save error code */
 569:     close(ttyfd);
 570:     ttyfd = -1;
 571:     errno = i;          /* and report this error */
 572: #ifdef EXCELAN
 573:     if (errno) experror("netopen connect");
 574: #else
 575: #ifdef MULTINET
 576:     debug(F101,"netopen connect error","",socket_errno);
 577:     if (errno) socket_perror("netopen connect");
 578: #else
 579:     debug(F101,"netopen connect errno","",errno);
 580: #ifdef  WINTCP
 581:     perror("netopen connect");
 582: #endif	/* WINTCP */
 583: #ifdef DEC_TCPIP
 584:     perror("netopen connect");
 585: #endif /* DEC_TCPIP */
 586: #endif /* MULTINET */
 587: #endif /* EXCELAN */
 588:     return(-1);
 589:     }
 590: #ifdef SO_OOBINLINE
 591: /*
 592:   The symbol SO_OOBINLINE is not known to Ultrix 2.0.
 593:   It means "leave out of band data inline".  The normal value is 0x0100,
 594:   but don't try this on systems where the symbol is undefined.
 595: */
 596: #ifdef datageneral
 597:     setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
 598: #else
 599: #ifdef BSD43
 600:     setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
 601: #else
 602: #ifdef OSF1
 603:     setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
 604: #else
 605: #ifdef POSIX
 606:     setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
 607: #else
 608: #ifdef SOLARIS
 609: /*
 610:   Maybe this applies to all SVR4 versions, but the other (else) way has been
 611:   compiling and working fine on all the others, so best not to change it.
 612: */
 613:     setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
 614: #else
 615:     setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE, &on, sizeof on);
 616: #endif /* SOLARIS */
 617: #endif /* POSIX */
 618: #endif /* BSD43 */
 619: #endif /* OSF1 */
 620: #endif /* datageneral */
 621: #endif /* SO_OOBINLINE */
 622: 
 623:     /* See if the service is TELNET. */
 624:     if ((x = ntohs((unsigned short)service->s_port)) == TELNET_PORT)
 625:       ttnproto = NP_TELNET;     /* Yes, set global flag. */
 626:     debug(F101,"netopen service","",x);
 627:     ttnet = nett;           /* TCP/IP (sockets) network */
 628:     tn_init = 0;            /* Telnet protocol not init'd yet */
 629:     if (*lcl < 0) *lcl = 1;     /* Local mode. */
 630:     return(0);              /* Done. */
 631: }
 632: 
 633: /*  N E T C L O S  --  Close current network connection.  */
 634: 
 635: int
 636: netclos() {
 637:     int x = 0;
 638:     if (ttyfd < 0)          /* Was open? */
 639:       return(0);            /* Wasn't. */
 640:     if (ttyfd > -1)         /* Was. */
 641: #ifdef VMSTCPIP
 642:       x = socket_close(ttyfd);      /* Close it. */
 643: #else
 644:       x = close(ttyfd);
 645: #endif /* VMSTCPIP */
 646:     ttyfd = -1;             /* Mark it as closed. */
 647:     tn_init = 0;            /* Remember about telnet protocol... */
 648:     *ipaddr = '\0';         /* Zero the IP address string */
 649:     return(x);
 650: }
 651: 
 652: /*  N E T T C H K  --  Check if network up, and how many bytes can be read */
 653: /*
 654:   Returns number of bytes waiting, or -1 if connection has been dropped.
 655: */
 656: int                 /* Check how many bytes are ready */
 657: nettchk() {             /* for reading from network */
 658: #ifdef VMSTCPIP
 659:     unsigned int count;
 660:     int x, y;
 661:     char c;
 662: 
 663:     debug(F101,"nettchk entry ttibn","",ttibn);
 664:     debug(F101,"nettchk entry ttibp","",ttibp);
 665:     socket_errno = 0;
 666: /*
 667:   Note: this socket_ioctl() call does NOT return an error if the
 668:   connection has been broken.  (At least not in Multinet.)
 669: */
 670:     if (socket_ioctl(ttyfd,FIONREAD,&count) < 0) {
 671:     debug(F101,"nettchk socket_ioctl error","",socket_errno);
 672:     if (ttibn < 1) return(-1);
 673:     else return(ttibn);
 674:     }
 675:     debug(F101,"nettchk count","",count);
 676: 
 677: #ifndef DEC_TCPIP
 678: /*
 679:   Let's see if we can skip this for UCX, since it seems to cause trouble.
 680: */
 681:     if (count == 0) {
 682: /*
 683:   Here we need to tell the difference between a 0 count on an active
 684:   connection, and a 0 count because the remote end of the socket broke the
 685:   connection.  There is no mechanism in TGV MultiNet (or WIN/TCP?) to query
 686:   the status of the connection, so we have to do a read.  -1 means there was
 687:   no data available (socket_errno == EWOULDBLOCK), 0 means the connection is
 688:   down.  But if, by chance, we actually get a character, we have to put it
 689:   where it won't be lost.
 690: */
 691:     y = 1;              /* Turn on nonblocking reads */
 692:     debug(F101,"nettchk before FIONBIO","",x);
 693:     x = socket_ioctl(ttyfd,FIONBIO,&y);
 694:     debug(F101,"nettchk FIONBIO","",x);
 695:     x = socket_read(ttyfd,&c,1);    /* Returns -1 if no data */
 696:     debug(F101,"nettchk socket_read","",x);
 697:     y = 0;              /* Turn them back off */
 698:     socket_ioctl(ttyfd,FIONBIO,&y);
 699:     if (x == 0) return(-1);     /* Connection is broken. */
 700:     if (x == 1) {           /* Oops, actually got a byte? */
 701:         debug(F101,"nettchk socket_read char","",c);
 702:         debug(F101,"nettchk ttibp","",ttibp);
 703:         debug(F101,"nettchk ttibn","",ttibn);
 704: /*
 705:   So put the byte we got into the buffer at the current position.
 706:   Increment the buffer count, but DON'T increment the buffer pointer.
 707: */
 708:         ttibuf[ttibp+ttibn] = c;
 709:         ttibn++;
 710: #ifdef DEBUG
 711:         ttibuf[ttibp+ttibn] = '\0';
 712:         debug(F111,"nettchk ttibn",ttibuf,ttibn);
 713: #endif /* DEBUG */
 714:     }
 715:     }
 716: #endif /* DEC_TCPIP */
 717:     debug(F101,"nettchk returns","",count+ttibn);
 718:     return(count + ttibn);
 719: 
 720: #else /* Not VMSTCPIP */
 721: /*
 722:   UNIX just uses ttchk(), in which the ioctl() calls on the file descriptor
 723:   seem to work OK.
 724: */
 725:     return(0);
 726: #endif /* VMSTCPIP */
 727: /*
 728:   But what about X.25?
 729: */
 730: }
 731: 
 732: /*  N E T I N C --  Input character from network */
 733: 
 734: int
 735: netinc(timo) int timo; {
 736: #ifdef VMSTCPIP
 737:     int x; unsigned char c;     /* The locals. */
 738: 
 739:     if (ttibn > 0) {            /* Something in internal buffer? */
 740:     debug(F100,"netinc char in buf","",0); /* Yes. */
 741:     x = 0;              /* Success. */
 742:     } else {                /* Else must read from network. */
 743:     x = -1;             /* Assume failure. */
 744: #ifdef DEBUG
 745:     debug(F101,"netinc goes to net, timo","",timo);
 746:     ttibuf[ttibp+1] = '\0';
 747:     debug(F111,"netinc ttibuf",ttibuf,ttibp);
 748: #endif /* DEBUG */
 749:     if (timo <= 0) {        /* Untimed case. */
 750:         while (1) {         /* Wait forever if necessary. */
 751:         if (ttbufr() < 0)   /* Refill buffer. */
 752:           break;        /* Error, fail. */
 753:         if (ttibn > 0) {    /* Success. */
 754:             x = 0;
 755:             break;
 756:         }
 757:         }
 758:     } else {            /* Timed case... */
 759:         saval = signal(SIGALRM,ttimoff); /* Enable timer interrupt */
 760:         alarm(timo);        /* for requested interval. */
 761:         if (setjmp(njbuf)) {    /* Timer went off? */
 762:         x = -1;         /* Yes, fail. */
 763:         } else {
 764:         while (1) {
 765:             if (ttbufr() < 0)   /* Keep trying to refill it. */
 766:               break;        /* Till we get an error. */
 767:             if (ttibn > 0) {    /* Or we get a character. */
 768:             x = 0;
 769:             break;
 770:             }
 771:         }
 772:         }
 773:         ttimoff();          /* Timer off. */
 774:     }
 775:     }
 776:     if (x < 0) {            /* Return -1 if we failed. */
 777:     debug(F100,"netinc timed out","",0);
 778:     return(-1);
 779:     } else {                /* Otherwise */
 780:     ttibn--;            /* Return what we got. */
 781:     c = ttibuf[ttibp++];
 782:     debug(F101,"netinc returning","",c);
 783:     return((c & 0xff));
 784:     }
 785: #else /* Not MULTINET or WINTCP */
 786:     return(-1);
 787: #endif /* VMSTCPIP */
 788: }
 789: 
 790: /*  N E T T O L  --  Output a string of bytes to the network  */
 791: /*
 792:   Call with s = pointer to string, n = length.
 793:   Returns number of bytes actually written on success, or
 794:   -1 on i/o error, -2 if called improperly.
 795: */
 796: int
 797: nettol(s,n) char *s; int n; {
 798: #ifdef VMSTCPIP
 799:     int count;
 800:     if (ttnet == NET_TCPB) {
 801:     if ((count = socket_write(ttyfd,s,n)) < 1) {
 802:         debug(F101,"nettol socket_write error","",socket_errno);
 803:         return(-1);
 804:     }
 805:     debug(F111,"nettol socket_write",s,count);
 806:     return(count);
 807:     } else return(-2);
 808: #else
 809:     debug(F100,"nettol VMSTCPIP not defined","",0);
 810:     return(-2);
 811: #endif /* VMSTCPIP */
 812: }
 813: 
 814: /*  N E T T O C  --   Output character to network */
 815: /*
 816:   Call with character to be transmitted.
 817:   Returns 0 if transmission was successful, or
 818:   -1 upon i/o error, or -2 if called improperly.
 819: */
 820: int
 821: #ifdef CK_ANSIC
 822: nettoc(char c)
 823: #else
 824: nettoc(c) char c;
 825: #endif /* CK_ANSIC */
 826: /* nettoc */ {
 827: #ifdef VMSTCPIP
 828:     unsigned char cc;
 829:     cc = c;
 830:     if (ttnet == NET_TCPB) {
 831:     debug(F101,"nettoc cc","",cc);
 832:     if (socket_write(ttyfd,&cc,1) < 1) {
 833:         debug(F101,"nettoc socket_write error","",socket_errno);
 834:         return(-1);
 835:     }
 836:     debug(F101,"nettoc socket_write","", cc);
 837:     return(0);
 838:     } else return(-2);
 839: #else
 840:     return(-2);
 841: #endif /* MULTINET */
 842: }
 843: 
 844: /*  N E T F L U I  --  Flush network input buffer  */
 845: 
 846: int
 847: netflui() {
 848:     int n;
 849: #ifdef VMSTCPIP
 850:     ttibuf[ttibp+1] = '\0';
 851:     debug(F111,"netflui 1",ttibuf,ttibn);
 852:     ttibn = ttibp = 0;          /* Flush internal buffer *FIRST* */
 853:     if ((n = nettchk()) > 0) {      /* Now see what's waiting on the net */
 854:     if (n > TTIBUFL) n = TTIBUFL;   /* and sponge it up */
 855:     debug(F101,"netflui 2","",n);   /* ... */
 856:     n = socket_read(ttyfd,ttibuf,n) ; /* into our buffer */
 857:     if (n >= 0) ttibuf[n] = '\0';
 858:     debug(F111,"netflui 3",ttibuf,n);
 859:     ttibuf[0] = '\0';
 860:     }
 861: #else
 862: /*
 863:   It seems the UNIX ioctl()s don't do the trick, so we have to read the
 864:   stuff ourselves.  This should be pretty much portable, if not elegant.
 865: */
 866:     if ((n = ttchk()) > 0) {
 867:     debug(F101,"netflui","",n);
 868:     while ((n--) && ttinc(0) > -1) ; /* Don't worry, it's buffered. */
 869:     }
 870: #endif /* VMSTCPIP */
 871:     return(0);
 872: }
 873: 
 874: #ifdef TNCODE               /* Compile in telnet support code */
 875: 
 876: /* TCP/IP Telnet negotiation support code */
 877: 
 878: static int sgaflg = 0;          /* telnet SGA flag */
 879: static int wttflg = 0;          /* telnet terminal type flag */
 880: 
 881: #ifndef TELCMDS
 882: char *telcmds[] = {
 883:     "SE", "NOP", "DMARK", "BRK",  "IP",   "AO", "AYT",  "EC",
 884:     "EL", "GA",  "SB",    "WILL", "WONT", "DO", "DONT", "IAC",
 885: };
 886: int ntelcmds = sizeof(telcmds) / sizeof(char *);
 887: #endif /* TELCMDS */
 888: 
 889: #ifndef TELOPTS
 890: char *telopts[] = {
 891:     "BINARY", "ECHO", "RCP", "SUPPRESS GO AHEAD", "NAME",
 892:     "STATUS", "TIMING MARK", "RCTE", "NAOL", "NAOP",
 893:     "NAOCRD", "NAOHTS", "NAOHTD", "NAOFFD", "NAOVTS",
 894:     "NAOVTD", "NAOLFD", "EXTEND ASCII", "LOGOUT", "BYTE MACRO",
 895:     "DATA ENTRY TERMINAL", "SUPDUP", "SUPDUP OUTPUT",
 896:     "SEND LOCATION", "TERMINAL TYPE", "END OF RECORD"
 897: #ifdef TELOPT_TUID
 898:     ,"TACACS UID"
 899: #ifdef TELOPT_OUTMRK
 900:     ,"OUTPUT MARKING"
 901: #ifdef TELOPT_TTYLOC
 902:     ,"TTYLOC"
 903: #ifdef TELOPT_3270REGIME
 904:     ,"3270 REGIME"
 905: #ifdef TELOPT_X3PAD
 906:     ,"X.3 PAD"
 907: #ifdef TELOPT_NAWS
 908:     ,"NAWS"
 909: #ifdef TELOPT_TSPEED
 910:     ,"TSPEED"
 911: #ifdef TELOPT_LFLOW
 912:     ,"LFLOW"
 913: #ifdef TELOPT_LINEMODE
 914:     ,"LINEMODE"
 915: #endif
 916: #endif
 917: #endif
 918: #endif
 919: #endif
 920: #endif
 921: #endif
 922: #endif
 923: #endif
 924: };
 925: #endif /* TELOPTS */
 926: 
 927: int ntelopts = sizeof(telopts) / sizeof(char *);
 928: #endif /* TNCODE */
 929: 
 930: 
 931: /* Send network BREAK */
 932: /*
 933:   Returns -1 on error, 0 if nothing happens, 1 if BREAK sent successfully.
 934: */
 935: int
 936: netbreak() {
 937:     CHAR buf[3];
 938:     if (ttnet == NET_TCPB) {
 939:     if (ttnproto == NP_TELNET) {
 940: #ifdef TNCODE
 941:         buf[0] = (CHAR) IAC; buf[1] = (CHAR) BREAK;
 942:         if (ttol(buf,2) < 2) return(-1);
 943:         debug(F101,"telnet BREAK ok","",BREAK);
 944:         return(1);
 945: #else
 946:         debug(F100,"netbreak no TNCODE","",0);
 947:         return(0);
 948: #endif /* TNCODE */
 949:     }
 950:     /* Insert other TCP/IP protocols here */
 951:     }
 952:     /* Insert other networks here */
 953:     return(0);
 954: }
 955: 
 956: /* Send a telnet option, avoid loops. */
 957: /* Returns 1 if command was sent, 0 if not, -1 on error */
 958: 
 959: int
 960: tn_sopt(cmd,opt) int cmd, opt; {    /* TELNET SEND OPTION */
 961:     CHAR buf[4];
 962:     int n;
 963:     if (ttnet != NET_TCPB) return(0);   /* Must be TCP/IP */
 964:     if (ttnproto != NP_TELNET) return(0); /* Must be telnet protocol */
 965:     n = cmd - SE;
 966:     if (n < 0 || n > ntelcmds) return(0);
 967: #ifdef TNCODE
 968:     buf[0] = (CHAR) IAC;
 969:     buf[1] = (CHAR) cmd & 0xff;
 970:     buf[2] = (CHAR) opt & 0xff;
 971:     if (ttol(buf,3) < 3)
 972:       return(-1);
 973:     debug(F111,"telnet cmd >",telcmds[n],cmd);
 974:     debug(F111,"telnet opt >",
 975:       (opt < ntelopts) ? telopts[opt] : "UNKNOWN", opt );
 976:     if (debses && cmd != SB)
 977:       printf("[%s %s]",telcmds[n],
 978:          (opt < ntelopts) ? telopts[opt] : "UNKNOWN");
 979:     return(1);
 980: #else
 981:     debug(F100,"tn_sopt no TNCODE","",0);
 982:     return(0);
 983: #endif /* TNCODE */
 984: }
 985: 
 986: /* Initialize a telnet connection. */
 987: /* Returns -1 on error, 0 if nothing happens, 1 if init msgs sent ok */
 988: 
 989: int
 990: tn_ini() {
 991: #ifndef TNCODE
 992:     debug(F100,"tn_ini no TNCODE","",0);
 993:     return(0);
 994: #else /* TELNET protocol support */
 995:     debug(F101,"tn_ini ttnproto","",ttnproto);
 996:     debug(F101,"tn_ini tn_init","",tn_init);
 997: 
 998:     if (ttnet != NET_TCPB)      /* Make sure connection is TCP/IP. */
 999:       return(0);
1000:     if (tn_init)            /* Have we done this already? */
1001:       return(0);            /* Don't do it again. */
1002:     debug(F101,"tn_ini tn_duplex","",tn_duplex);
1003:     duplex = tn_duplex;         /* Assume local echo. */
1004:     sgaflg = 0;             /* Assume Go-Ahead suppressed. */
1005:     wttflg = 0;             /* Did not send WILL TERM TYPE yet. */
1006:     if (ttnproto == NP_NONE) {      /* If not talking to a telnet port, */
1007:     ttnproto = NP_TELNET;       /* pretend it's telnet anyway, */
1008:     tn_init = 1;            /* but don't send initial options. */
1009:     debug(F100,"tn_ini skipping telnet negotiations","",0);
1010:     return(0);
1011:     }
1012:     /* Talking to telnet port, so send WILL TERMINAL TYPE and DO SGA */
1013: 
1014:     if (tn_sopt(WILL,TELOPT_TTYPE) < 0) /* Will send terminal type. */
1015:       return(-1);
1016:     wttflg = 1;             /* Remember I said I would. */
1017:     if (tn_sopt(DO,TELOPT_SGA) < 0) /* Please suppress go-ahead. */
1018:       return(-1);
1019: #ifdef COMMENT
1020:     if (tn_sopt(DO,TELOPT_ECHO) < 0)    /* Ask the server to echo, since */
1021:       return(-1);           /* I'm assuming it will. */
1022: #endif /* COMMENT */
1023:     tn_init = 1;            /* Set telnet-initialized flag. */
1024: 
1025:     /* Don't send anthing else! */
1026: 
1027:     debug(F101,"tn_ini duplex","",duplex);
1028:     return(1);
1029: #endif /* TNCODE */
1030: }
1031: 
1032: /*
1033:   Process in-band Telnet negotiation characters from the remote host.
1034:   Call with the telnet IAC character and the current duplex setting
1035:   (0 = remote echo, 1 = local echo).
1036:   Returns:
1037:     3 if server has sent us a quoted IAC
1038:     2 if local echo must be changed to remote
1039:     1 if remote echo must be changed to local
1040:     0 if nothing happens or no action necessary
1041:    -1 on failure (= internal or i/o error)
1042: */
1043: 
1044: #define TSBUFSIZ 41
1045: char sb[TSBUFSIZ];          /* Buffer for subnegotiations */
1046: 
1047: int
1048: #ifdef CK_ANSIC             /* TELNET DO OPTION */
1049: tn_doop( CHAR z, int echo, int (*fn)(int) )
1050: #else
1051: tn_doop(z, echo, fn) CHAR z; int echo; int (*fn)();
1052: #endif /* CK_ANSIC */
1053: /* tn_doop */ {
1054:     int c, x, y, n, m, flag;
1055: 
1056: #ifndef TNCODE
1057:     debug(F100,"tn_doop no TNCODE","",0);
1058:     return(0);
1059: #else
1060:     if (z != (CHAR) IAC) {
1061:     debug(F101,"tn_doop bad call","",z);
1062:     return(-1);
1063:     }
1064:     if (ttnet != NET_TCPB) return(0);
1065:     if (ttnproto != NP_TELNET) return(0);   /* Check protocol */
1066: 
1067: /* Have IAC, read command character. */
1068: 
1069:     c = (*fn)(0) & 0xff;        /* Read command character */
1070:     m = c - SE;             /* Check validity */
1071:     if (m < 0 || m > ntelcmds) {
1072:     debug(F101,"tn_doop bad cmd","",c);
1073:     return(0);
1074:     }
1075:     if (seslog) {           /* Copy to session log, if any. */
1076:     if (zchout(ZSFILE, (char) z) < 0) seslog = 0; /* Log IAC. */
1077:     else if (zchout(ZSFILE, (char) c) < 0) seslog = 0; /* Log command */
1078:     }
1079:     debug(F111,"telnet cmd <",telcmds[m],c); /* Debug log. */
1080: 
1081:     if (c == (CHAR) IAC) return(3); /* Quoted IAC */
1082:     if (c < SB) return(0);      /* Other command with no arguments. */
1083: 
1084: /* SB, WILL, WONT, DO, or DONT need more bytes... */
1085: 
1086:     if ((x = (*fn)(0)) < 0) return(-1); /* Get the option. */
1087:     x &= 0xff;              /* Trim to 8 bits. */
1088: 
1089:     debug(F111,"telnet opt <",
1090:       (x < ntelopts) ? telopts[x] : "UNKNOWN", x );
1091:     if (seslog)             /* Session log */
1092:       if (zchout(ZSFILE, (char) x) < 0) seslog = 0;
1093: 
1094:     /* Now handle the command */
1095: 
1096:     if (debses && c != SB)      /* Debug to screen. */
1097:       printf("<%s %s>",telcmds[m],
1098:          (x < ntelopts) ? telopts[x] : "UNKNOWN" );
1099:     switch (x) {
1100:       case TELOPT_ECHO:         /* ECHO negotiation. */
1101:     switch (c) {            /* Command */
1102:       case WILL:            /* Host says it will echo. */
1103:         if (echo)           /* Only reply if change required. */
1104:           return((tn_sopt(DO,x) < 0) ? -1 : 2); /* Please do. */
1105:         else return(0);     /* Otherwise no change. */
1106:       case WONT:            /* Host says it won't echo. */
1107:         if (!echo)          /* If I'm full duplex */
1108:           return ((tn_sopt(DONT,x) < 0) ? -1 : 1); /* Switch to half */
1109:         else return(0);     /* Otherwise, no change.  */
1110:       case DO:          /* Host wants me to echo */
1111:         if (tn_sopt(WONT,x) < 0)    /* but the client never echoes */
1112:           return(-1);       /* back to the server. */
1113:       default:          /* Don't reply to anything else */
1114:         return(0);
1115:     }
1116: 
1117:       case TELOPT_SGA:          /* Suppress Go-Ahead */
1118:     switch (c) {            /* Command... */
1119:       case WONT:            /* Host says it won't. */
1120:         if (!sgaflg) {
1121:         sgaflg = 1;     /* Remember. */
1122:         if (tn_sopt(DONT,x) < 0) /* acknowledge, */
1123:           return(-1);
1124:         }
1125:         return(echo ? 0 : 1);   /* Switch to half duplex */
1126:       case WILL:            /* Server says it will SGA */
1127:         if (sgaflg) {       /* ACK only if necessary */
1128:         if (tn_sopt(DO,x) < 0)
1129:           return(-1);
1130:         sgaflg = 0;     /* Remember new SGA state. */
1131:         }
1132:         return(0);          /* But don't change echo state. */
1133:     }
1134: 
1135: #ifdef TELOPT_TTYPE
1136:       case TELOPT_TTYPE:        /* Terminal Type */
1137:     switch (c) {
1138:       case DO:          /* DO terminal type. */
1139:         if (wttflg == 0) {      /* If I haven't said so before, */
1140:         if (tn_sopt((CHAR)WILL,x) < 0) /* say I'll send it if asked. */
1141:           return(-1);
1142:         wttflg++;
1143:         }
1144:         return(0);
1145:       case SB:
1146:         debug(F100,"TELNET subnegotiation:","",0);
1147:         n = flag = 0;       /* Flag for when done reading SB */
1148:         while (n < TSBUFSIZ) {  /* Loop looking for IAC SE */
1149:         if ((y = (*fn)(0)) < 0) /* Read a byte */
1150:           return(-1);
1151:         y &= 0xff;      /* Make sure it's just 8 bits. */
1152:         sb[n++] = y;        /* Deposit in buffer. */
1153:         if (seslog)     /* Take care of session log */
1154:           if (zchout(ZSFILE, (char) y) < 0)
1155:             seslog = 0;
1156:         if (y == IAC) {     /* If this is an IAC */
1157:             if (flag) {     /* If previous char was IAC */
1158:             n--;        /* it's quoted, keep one IAC */
1159:             flag = 0;   /* and turn off the flag. */
1160:             } else flag = 1;    /* Otherwise set the flag. */
1161:         } else if (flag) {  /* Something else following IAC */
1162:             if (y != SE)    /* If not SE, it's a protocol error */
1163:               flag = 0;
1164:             break;
1165:         }
1166:         }
1167:         if (!flag) {        /* Make sure we got a valid SB */
1168:         debug(F100, "TELNET Subnegotian prematurely broken", "",0);
1169:         return(-1);
1170:         }
1171:         if (debses) {       /* Debug to screen. */
1172:         int i;
1173:         printf("<SB %s ",telopts[TELOPT_TTYPE]);
1174:         for (i = 0; i < n-2; i++) printf("%02x",sb[i]);
1175:         printf(" IAC SE>");
1176:         }
1177:         debug(F101,"TELNET suboption<","",sb[0]);
1178:         if (sb[0] == 1) {       /* SEND terminal type? */
1179:         if (tn_sttyp() < 0) /* Yes, so send it. */
1180:           return(-1);
1181:         }
1182:       default:          /* Others, ignore */
1183:         return(0);
1184:     }
1185: #endif /* TELOPT_TTYPE */
1186: 
1187:       default:              /* All others: refuse */
1188:     switch(c) {
1189:       case WILL:            /* You will? */
1190:         if (tn_sopt(DONT,x) < 0)    /* Please don't. */
1191:           return(-1);       /* (Could this cause a loop?) */
1192:         break;
1193:       case DO:          /* You want me to? */
1194:         if (tn_sopt(WONT,x) < 0)    /* I won't. */
1195:           return(-1);
1196:         break;
1197:       case DONT:            /* You don't want me to? */
1198:         if (tn_sopt(WONT,x) < 0)    /* I won't. */
1199:           return(-1);       /* (Could this cause a loop?) */
1200:       case WONT:            /* You won't? */
1201:         break;          /* I didn't want you to. */
1202:     }               /* Anything else, treat as user data */
1203:     return(0);
1204:     }
1205: #endif /* TNCODE */
1206: }
1207: 
1208: /* Telnet send terminal type */
1209: /* Returns -1 on error, 0 if nothing happens, 1 if type sent successfully */
1210: 
1211: int
1212: tn_sttyp() {                /* Send telnet terminal type. */
1213: #ifndef TNCODE
1214:     debug(F100,"tn_sttyp no TNCODE","",0);
1215:     return(0);
1216: #else
1217:     char *ttn; int ttl, i;      /* Name & length of terminal type. */
1218: 
1219:     if (ttnet != NET_TCPB) return(0);
1220:     if (ttnproto != NP_TELNET) return(0);
1221: 
1222:     ttn = NULL;
1223: 
1224:     if (tn_term) {          /* Terminal type override? */
1225:     debug(F110,"tn_sttyp",tn_term,0);
1226:     if (*tn_term) ttn = tn_term;
1227:     } else debug(F100,"tn_sttyp no term override","",0);
1228: #ifndef datageneral
1229:     if (!ttn)               /* If no override, */
1230:       ttn = getenv("TERM");     /* get it from the environment. */
1231: #endif /* datageneral */
1232:     if ((ttn == ((char *)0)) || ((ttl = (int)strlen(ttn)) >= TSBUFSIZ)) {
1233:     ttn = "UNKNOWN";
1234:     ttl = 7;
1235:     }
1236:     sb[0] = IAC;            /* I Am a Command */
1237:     sb[1] = SB;             /* Subnegotiation */
1238:     sb[2] = TELOPT_TTYPE;       /* Terminal Type */
1239:     sb[3] = (CHAR) 0;           /* Is... */
1240:     for (i = 4; *ttn; ttn++,i++)    /* Copy and uppercase it */
1241:       sb[i] = (islower(*ttn)) ? toupper(*ttn) : *ttn;
1242:     ttn = sb;               /* Point back to beginning */
1243:     sb[i++] = IAC;          /* End of Subnegotiation */
1244:     sb[i++] = SE;           /* marked by IAC SE */
1245:     if (ttol((CHAR *)sb,i) < 0)     /* Send it. */
1246:       return(-1);
1247: #ifdef DEBUG
1248:     sb[i-2] = '\0';         /* For debugging */
1249:     debug(F111,"telnet SB sent ttype",sb+4,ttl);
1250: #endif /* DEBUG */
1251:     if (debses)             /* Debug to screen. */
1252:       printf("[SB TERMINAL TYPE 00 %s IAC SE]",sb+4);
1253:     return(1);
1254: #endif /* TNCODE */
1255: }
1256: 
1257: #ifdef SUNX25
1258: /*
1259:   SunLink X.25 support by Marcello Frutig, Catholic University,
1260:   Rio de Janeiro, Brazil, 1990.
1261: */
1262: 
1263: /* PAD X.3, X.28 and X.29 support */
1264: 
1265: static CHAR x29err [MAXPADPARMS+3] = { X29_ERROR, INVALID_PAD_PARM, '\0' };
1266: 
1267: 
1268: /* Initialize PAD */
1269: 
1270: extern CHAR padparms[MAXPADPARMS+1];
1271: 
1272: VOID
1273: initpad() {
1274:   padparms[PAD_BREAK_CHARACTER]        = 0;  /* Break character */
1275:   padparms[PAD_ESCAPE]                 = 1;  /* Escape permitted */
1276:   padparms[PAD_ECHO]                   = 1;  /* Kermit PAD does echo */
1277:   padparms[PAD_DATA_FORWARD_CHAR]      = 2;  /* forward character CR */
1278:   padparms[PAD_DATA_FORWARD_TIMEOUT]   = 0;  /* no timeout forward condition */
1279:   padparms[PAD_FLOW_CONTROL_BY_PAD]    = 0;  /* not used */
1280:   padparms[PAD_SUPPRESSION_OF_SIGNALS] = 1;  /* allow PAD service signals */
1281:   padparms[PAD_BREAK_ACTION]           = 21; /* brk action: INT pk + brk ind*/
1282:   padparms[PAD_SUPPRESSION_OF_DATA]    = 0;  /* no supression of user data */
1283:   padparms[PAD_PADDING_AFTER_CR]       = 0;  /* no padding after CR */
1284:   padparms[PAD_LINE_FOLDING]           = 0;  /* no line fold */
1285:   padparms[PAD_LINE_SPEED]             = 0;  /* line speed - don't care */
1286:   padparms[PAD_FLOW_CONTROL_BY_USER]   = 0;  /* flow cont of PAD - not used */
1287:   padparms[PAD_LF_AFTER_CR]            = 0;  /* no LF insertion after CR */
1288:   padparms[PAD_PADDING_AFTER_LF]       = 0;  /* no padding after LF */
1289:   padparms[PAD_EDITING]                = 1;  /* can edit */
1290:   padparms[PAD_CHAR_DELETE_CHAR]       = 8;  /* character delete character */
1291:   padparms[PAD_BUFFER_DELETE_CHAR]     = 21; /* buffer delete character */
1292:   padparms[PAD_BUFFER_DISPLAY_CHAR]    = 18; /* buffer display character */
1293: }
1294: 
1295: 
1296: /* Set PAD parameters */
1297: 
1298: VOID
1299: setpad(s,n) CHAR *s; int n; {
1300:     int i;
1301:     CHAR *ps = s;
1302: 
1303:     for (i = 0; i < n; i++) {
1304:         if (*ps > MAXPADPARMS)
1305:       x29err[i+2] = *ps;
1306:         else
1307:       padparms[*ps] = *(ps+1);
1308:         ps += 2;
1309:     }
1310: }
1311: 
1312: /* Read PAD parameters */
1313: 
1314: VOID
1315: readpad(s,n,r) CHAR *s; int n; CHAR *r; {
1316:     int i;
1317:     CHAR *ps = s;
1318:     CHAR *pr = r;
1319: 
1320:     *pr++ = X29_PARAMETER_INDICATION;
1321:     for (i = 0; i < n; i++, ps++) {
1322:          if (*ps > MAXPADPARMS) {
1323:              x29err[i+2] = *ps++;
1324:          } else {
1325:              *pr++ = *ps;
1326:              *pr++ = padparms[*ps++];
1327:          }
1328:     }
1329: }
1330: 
1331: int
1332: qbitpkt(s,n) CHAR *s; int n; {
1333:     CHAR *ps = s;
1334:     int x29cmd = *ps;
1335:     CHAR *psa = s+1;
1336:     CHAR x29resp[(MAXPADPARMS*2)+1];
1337: 
1338:     switch (x29cmd) {
1339: 
1340:         case X29_SET_PARMS:
1341:             setpad (ps+1,n/2);
1342:             if ((int)strlen(x29err) > 2) {
1343:                 ttol (x29err,(int)strlen(x29err));
1344:                 x29err[2] = '\0';
1345:             }
1346:             return (-2);
1347:         case X29_READ_PARMS:
1348:             readpad (ps+1,n/2,x29resp);
1349:             setqbit ();
1350:             ttol (x29resp,n+1);
1351:             if ((int)strlen(x29err) > 2) {
1352:                 ttol (x29err,(int)strlen(x29err));
1353:                 x29err[2] = '\0';
1354:             }
1355:             resetqbit();
1356:             break;
1357:         case X29_SET_AND_READ_PARMS:
1358:             setpad (ps+1,n/2);
1359:             readpad (ps+1,n/2,x29resp);
1360:             setqbit();
1361:             ttol (x29resp,n+1);
1362:             if ((int)strlen(x29err) > 2) {
1363:                 ttol (x29err,(int)strlen(x29err));
1364:                 x29err [2] = '\0';
1365:             }
1366:             resetqbit();
1367:             return (-2);
1368:         case X29_INVITATION_TO_CLEAR:
1369:             (VOID) x25clear();
1370:             return (-1) ;
1371:         case X29_INDICATION_OF_BREAK:
1372:         break;
1373:     }
1374:     return (0);
1375: }
1376: 
1377: /* PAD break action processor */
1378: 
1379: VOID
1380: breakact() {
1381:     extern char x25obuf[MAXOX25];
1382:     extern int obufl;
1383:     extern int active;
1384:     extern unsigned char tosend;
1385:     static CHAR indbrk[3] = {
1386:     X29_INDICATION_OF_BREAK,
1387:     PAD_SUPPRESSION_OF_DATA,
1388:     1
1389:     };
1390:     CHAR intudat, cause, diag;
1391: 
1392:     if (x25stat() < 0) return(0);   /* Ignore if no virtual call established */
1393: 
1394:     if (padparms[PAD_BREAK_ACTION] != 0) /* Forward condition */
1395:         if (ttol(x25obuf,obufl) < 0) {
1396:             perror ("\r\nCan't send characters");
1397:             active = 0;
1398:         } else {
1399:             bzero (x25obuf,sizeof(x25obuf));
1400:             obufl = 0;
1401:             tosend = 0;
1402:         };
1403: 
1404:     switch (padparms[PAD_BREAK_ACTION]) {
1405: 
1406:        case 0 : break;          /* do nothing */
1407:        case 1 : /* send interrupt packet with interrupt user data field = 1 */
1408:             intudat = 1;
1409:                 x25intr (intudat);
1410:                 break;
1411:        case 2 : /* send reset packet with cause and diag = 0 */
1412:         cause = diag = 0;
1413:                 x25reset (cause,diag);
1414:                 break;
1415:        case 5 : /* send interrupt packet with interrupt user data field = 0 */
1416:         intudat = 0;
1417:                 x25intr (intudat) ;
1418:                 setqbit ();
1419:             /* send indication of break without a parameter field */
1420:                 ttoc(X29_INDICATION_OF_BREAK);
1421:                 resetqbit ();
1422:                 break;
1423:        case 8 : active = 0;     /* leave data transfer */
1424:                 conol ("\r\n");
1425:                 break;
1426:        case 21: /* send interrupt packet with interrupt user data field = 0 */
1427:         intudat = 0;
1428:                 x25intr (intudat);
1429:                 setpad (indbrk+1,2);    /* set pad to discard input */
1430:                 setqbit ();
1431:         /* send indication of break with parameter field */
1432:                 ttol (indbrk,sizeof(indbrk));
1433:                 resetqbit ();
1434:                 break;
1435:      }
1436: }
1437: 
1438: /* X.25 support functions */
1439: 
1440: X25_CAUSE_DIAG diag;
1441: 
1442: /*
1443:   Convert a null-terminated string representing an X.121 address
1444:   to a packed BCD form.
1445: */
1446: 
1447: int
1448: pkx121(str,bcd) char *str; CHAR *bcd; {
1449:     int i, j;
1450:     u_char c;
1451: 
1452:     i = j = 0;
1453:     while (str[i]) {
1454:         if ( i >= 15 || str [i] < '0' || str [i] > '9' )
1455:       return (-1);
1456:         c = str [i] - '0';
1457:         if ( i & 1 )
1458:       bcd [j++] |= c;
1459:         else
1460:       bcd [j] = c << 4;
1461:         i++;
1462:     }
1463:     return (i);
1464: }
1465: 
1466: /* Reads and prints X.25 diagnostic */
1467: 
1468: int
1469: x25diag () {
1470:     int i;
1471: 
1472:     bzero ((char *)&diag,sizeof(diag));
1473:     if (ioctl(ttyfd,X25_RD_CAUSE_DIAG,&diag)) {
1474:         perror ("Reading X.25 diagnostic");
1475:         return(-1);
1476:     }
1477:     if (diag.datalen > 0) {
1478:         printf ("X.25 Diagnostic :");
1479:         for (i = 0; i < diag.datalen; i++) printf (" %02x",diag.data[i]);
1480:         printf ("\r\n");
1481:     }
1482:     return(0);
1483: }
1484: 
1485: /* X.25 Out-of-Band Signal Handler */
1486: 
1487: VOID
1488: x25oobh() {
1489:     int oobtype;
1490:     u_char oobdata;
1491: 
1492:     (VOID) signal(SIGURG,x25oobh);
1493:     do {
1494:         if (ioctl(ttyfd,X25_OOB_TYPE,&oobtype)) {
1495:             perror ("Getting signal type");
1496:             return;
1497:         }
1498:         switch (oobtype) {
1499:       case INT_DATA:
1500:         if (recv(ttyfd,oobdata,1,MSG_OOB) < 0) {
1501:         perror ("Receiving X.25 interrupt data");
1502:         return;
1503:         }
1504:         printf ("\r\nInterrupt received, data = %d\r\n", oobdata);
1505:         break;
1506:       case VC_RESET:
1507:         printf ("\r\nVirtual circuit reset\r\n");
1508:         x25diag ();
1509:         break;
1510:       case N_RESETS:
1511:         printf ("\r\nReset timeout\r\n");
1512:         break;
1513:       case N_CLEARS:
1514:         printf ("\r\nClear timeout\r\n");
1515:         break;
1516:       case MSG_TOO_LONG:
1517:         printf ("\r\nMessage discarded, too long\r\n");
1518:         break;
1519:       default:
1520:         if (oobtype) printf("\r\nUnknown oob type %d\r\n",oobtype);
1521:         break;
1522:     }
1523:     } while (oobtype);
1524: }
1525: 
1526: /* Send a X.25 interrupt packet */
1527: 
1528: int
1529: #ifdef CK_ANSIC
1530: x25intr(char intr)
1531: #else
1532: x25intr(intr) char intr;
1533: #endif /* CK_ANSIC */
1534: /* x25intr */ {
1535:     if (send(ttyfd,&intr,1,MSG_OOB) < 0) return(-1);
1536:     debug(F100,"X.25 intr","",0);
1537:     return(0);
1538: }
1539: 
1540: /* Reset X.25 virtual circuit */
1541: int
1542: #ifdef CK_ANSIC
1543: x25reset(char cause, char diagn)
1544: #else
1545: x25reset(cause, diagn) char cause; char diagn;
1546: #endif /* CK_ANSIC */
1547: /* x25reset */ {
1548:     bzero ((char *)&diag,sizeof(diag));
1549:     diag.flags   = 0;
1550:     diag.datalen = 2;
1551:     diag.data[0] = cause;
1552:     diag.data[1] = diagn;
1553:     if (ioctl(ttyfd,X25_WR_CAUSE_DIAG,&diag) < 0)
1554:       return(-1);
1555:     debug(F100,"X.25 reset","",0);
1556:     return(0);
1557: }
1558: 
1559: /* Clear X.25 virtual circuit */
1560: int
1561: x25clear() {
1562:     int i;
1563:     debug(F100,"X.25 clear","",0);
1564:     bzero ((char *)&diag,sizeof(diag));
1565:     diag.flags = (1 << DIAG_TYPE);
1566:     diag.datalen = 2;
1567:     diag.data[0] = 0;
1568:     diag.data[1] = 0;
1569:     ioctl (ttyfd,X25_WR_CAUSE_DIAG,&diag); /* Send Clear Request */
1570:     return(ttclos(0));          /* Close socket */
1571: }
1572: 
1573: /* X.25 status */
1574: int
1575: x25stat() {
1576:     if (ttyfd < 0) return (-1);
1577:     return(0);
1578: }
1579: 
1580: /* Set Q_BIT on */
1581: VOID
1582: setqbit() {
1583:     static int qbiton = 1 << Q_BIT;
1584:     ioctl (ttyfd,X25_SEND_TYPE,&qbiton);
1585: }
1586: 
1587: /* Set Q_BIT off */
1588: VOID
1589: resetqbit() {
1590:     static int qbitoff = 0;
1591:     ioctl (ttyfd,X25_SEND_TYPE,&qbitoff);
1592: }
1593: 
1594: /* Read n characters from X.25 circuit into buf */
1595: 
1596: int
1597: x25xin(n,buf) int n; CHAR *buf; {
1598:     register int x, c;
1599:     int qpkt;
1600: 
1601:     do {
1602:     x = read(ttyfd,buf,n);
1603:     if (buf[0] & (1 << Q_BIT)) { /* If Q_BIT packet, process it */
1604:         /* If return -1 : invitation to clear; -2 : PAD changes */
1605:         if ((c=qbitpkt(buf+1,x-2)) < 0) return(c);
1606:         qpkt = 1;
1607:     } else qpkt = 0;
1608:     } while (qpkt);
1609:     if (x > 0) buf[x] = '\0';
1610:     if (x < 1) x = -1;
1611:     debug(F101,"x25xin x","",x);
1612: 
1613:     return(x);
1614: }
1615: 
1616: #ifdef COMMENT /* NO LONGER NEEDED! */
1617: /* X.25 read a line */
1618: 
1619: int
1620: #ifdef PARSENSE
1621: #ifdef CK_ANSIC
1622: x25inl(CHAR *dest, int max,int timo, CHAR eol, CHAR start)
1623: #else
1624: x25inl(dest,max,timo,eol,start) int max,timo; CHAR *dest, eol, start;
1625: #endif /* CK_ANSIC */
1626: #else /* not PARSENSE */
1627: #ifdef CK_ANSIC
1628: x25inl(CHAR *dest, int max,int timo, CHAR eol)
1629: #else
1630: x25inl(dest,max,timo,eol) int max,timo; CHAR *dest, eol;
1631: #endif /* __SDTC__ */
1632: #endif /* PARSENSE */
1633: /* x25inl */ {
1634:     CHAR *pdest;
1635:     int pktype, goteol, rest, n;
1636:     int i, flag = 0;
1637:     extern int ttprty, ttpflg;
1638:     int ttpmsk;
1639: 
1640:     ttpmsk = (ttprty) ? 0177 : 0377;    /* Set parity stripping mask */
1641: 
1642:     debug(F101,"x25inl max","",max);
1643:     debug(F101,"x25inl eol","",eol);
1644:     pdest  = dest;
1645:     rest   = max;
1646:     goteol = 0;
1647:     do {
1648:     n = read(ttyfd,pdest,rest);
1649:     n--;
1650:     pktype = *pdest & 0x7f;
1651:     switch (pktype) {
1652:       case 1 << Q_BIT:
1653:         if (qbitpkt(pdest+1,--n) < 0) return(-2);
1654:         break;
1655:       default:
1656:         if (flag == 0) { /* if not in packet, search start */
1657:         for (i = 1; (i < n) &&
1658:              !(flag = ((dest[i] & 0x7f) == start));
1659:              i++);
1660:         if (flag == 0) { /* not found, discard junk */
1661:             debug(F101,"x25inl skipping","",n);
1662:             continue;
1663:         } else {        /* found, discard junk before start */
1664:             int k;
1665:             n = n - i + 1;
1666:             for (k = 1; k <= n; k++, i++) dest[k] = dest[i];
1667:         }
1668:         }
1669:         for (i = 0; (i < n) && /* search for eol */
1670:          !(goteol=(((*pdest = *(pdest+1)&ttpmsk)&0x7f)== eol));
1671:          i++,pdest++);
1672:         *pdest = '\0';
1673:         rest -= n;
1674:     }
1675:     } while ( (rest > 0) && (!goteol) );
1676: 
1677:     if (goteol) {
1678:     n = max - rest;
1679:     debug (F111,"x25inl X.25 got",(char *) dest,n);
1680:     if (timo) ttimoff();
1681:     if (ttpflg++ == 0 && ttprty == 0) {
1682:         if ((ttprty = parchk(dest,start,n)) > 0) {
1683:         int j;
1684:         debug(F101,"x25inl senses parity","",ttprty);
1685:         debug(F110,"x25inl packet before",(char *)dest,0);
1686:         ttpmsk = 0x7f;
1687:         for (j = 0; j < n; j++)
1688:           dest[j] &= 0x7f; /* Strip parity from packet */
1689:         debug(F110,"x25inl packet after ",dest,0);
1690:         } else {
1691:         debug(F101,"parchk","",ttprty);
1692:         if (ttprty < 0) { ttprty = 0; n = -1; }
1693:         }
1694:     }
1695:     ttimoff();
1696:     return(n);
1697:     }
1698:     ttimoff();
1699:     return(-1);
1700: }
1701: #endif /* COMMENT */
1702: #endif /* SUNX25 */
1703: 
1704: #endif /* NETCONN */

Defined functions

SIGTYP defined in line 75; never used
breakact defined in line 1379; used 1 times
gethostbyname defined in line 313; used 1 times
getservbyname defined in line 294; used 1 times
inet_addr defined in line 318; used 4 times
inet_ntoa defined in line 327; used 2 times
netbreak defined in line 935; used 1 times
netclos defined in line 635; used 6 times
netflui defined in line 846; used 1 times
netinc defined in line 734; never used
netopen defined in line 340; used 1 times
nettchk defined in line 656; used 3 times
nettoc defined in line 820; never used
nettol defined in line 796; never used
pkx121 defined in line 1447; used 1 times
qbitpkt defined in line 1331; used 2 times
readpad defined in line 1314; used 2 times
resetqbit defined in line 1588; used 4 times
setpad defined in line 1298; used 3 times
setqbit defined in line 1581; used 4 times
tn_sopt defined in line 959; used 12 times
tn_sttyp defined in line 1211; used 1 times
ttbufr defined in line 191; used 2 times
x25clear defined in line 1560; used 3 times
x25diag defined in line 1468; used 2 times
x25inl defined in line 1628; used 2 times
x25intr defined in line 1528; used 5 times
x25oobh defined in line 1487; used 3 times
x25reset defined in line 1541; used 3 times
x25stat defined in line 1574; used 5 times
x25xin defined in line 1596; used 2 times

Defined variables

VOID defined in line 1588; never used
cknetv defined in line 1; used 1 times
njbuf defined in line 113; used 1 times
ntelcmds defined in line 886; used 2 times
ntelopts defined in line 927; used 4 times
sb defined in line 1045; used 16 times
sgaflg defined in line 878; used 5 times
telcmds defined in line 882; used 5 times
telopts defined in line 890; used 6 times
tn_duplex defined in line 121; used 4 times
tn_init defined in line 120; used 8 times
tn_term defined in line 122; used 11 times
ttibp defined in line 179; used 11 times
ttibuf defined in line 178; used 16 times
ttnet defined in line 118; used 14 times
wttflg defined in line 879; used 4 times
x29err defined in line 1265; used 14 times

Defined struct's

hostent defined in line 288; used 6 times
servent defined in line 284; used 8 times

Defined macros

NAMECPYL defined in line 99; used 2 times
TELNET_PORT defined in line 264; used 1 times
TELOPT_TTYPE defined in line 268; used 5 times
TSBUFSIZ defined in line 1044; used 3 times
TTIBUFL defined in line 176; used 5 times
X29PID defined in line 355; used 1 times
bcopy defined in line 95; used 1 times
bzero defined in line 94; used 7 times
socket_close defined in line 53; used 1 times
socket_errno defined in line 48; used 11 times
socket_ioctl defined in line 50; used 3 times
socket_perror defined in line 52; used 2 times
socket_read defined in line 49; used 4 times
socket_write defined in line 51; used 2 times
Last modified: 1992-11-24
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 370
Valid CSS Valid XHTML 1.0 Strict