121182Sdist /* 2*61451Sbostic * Copyright (c) 1989, 1993 3*61451Sbostic * The Regents of the University of California. All rights reserved. 433687Sbostic * 542673Sbostic * %sccs.include.redist.c% 621182Sdist */ 721182Sdist 86295Sroot #ifndef lint 9*61451Sbostic static char copyright[] = 10*61451Sbostic "@(#) Copyright (c) 1989, 1993\n\ 11*61451Sbostic The Regents of the University of California. All rights reserved.\n"; 1233687Sbostic #endif /* not lint */ 136295Sroot 1421182Sdist #ifndef lint 15*61451Sbostic static char sccsid[] = "@(#)telnetd.c 8.1 (Berkeley) 06/04/93"; 1633687Sbostic #endif /* not lint */ 1721182Sdist 1838904Sborman #include "telnetd.h" 1945234Sborman #include "pathnames.h" 2038904Sborman 2160151Sdab #if defined(_SC_CRAY_SECURE_SYS) && !defined(SCM_SECURITY) 2260151Sdab /* 2360151Sdab * UNICOS 6.0/6.1 do not have SCM_SECURITY defined, so we can 2460151Sdab * use it to tell us to turn off all the socket security code, 2560151Sdab * since that is only used in UNICOS 7.0 and later. 2660151Sdab */ 2760151Sdab # undef _SC_CRAY_SECURE_SYS 2860151Sdab #endif 2960151Sdab 3057212Sdab #if defined(_SC_CRAY_SECURE_SYS) 3157212Sdab #include <sys/sysv.h> 3257212Sdab #include <sys/secdev.h> 3360151Sdab # ifdef SO_SEC_MULTI /* 8.0 code */ 3460151Sdab #include <sys/secparm.h> 3560151Sdab #include <sys/usrv.h> 3660151Sdab # endif /* SO_SEC_MULTI */ 3757212Sdab int secflag; 3857212Sdab char tty_dev[16]; 3957212Sdab struct secdev dv; 4057212Sdab struct sysv sysv; 4160151Sdab # ifdef SO_SEC_MULTI /* 8.0 code */ 4260151Sdab struct socksec ss; 4360151Sdab # else /* SO_SEC_MULTI */ /* 7.0 code */ 4457212Sdab struct socket_security ss; 4560151Sdab # endif /* SO_SEC_MULTI */ 4657212Sdab #endif /* _SC_CRAY_SECURE_SYS */ 4757212Sdab 4857212Sdab #if defined(AUTHENTICATION) 4946809Sdab #include <libtelnet/auth.h> 5046809Sdab int auth_level = 0; 5146809Sdab #endif 5246809Sdab #if defined(SecurID) 5346809Sdab int require_SecurID = 0; 5446809Sdab #endif 5546809Sdab 5657212Sdab extern int utmp_len; 5757212Sdab int registerd_host_only = 0; 5857212Sdab 5957212Sdab #ifdef STREAMSPTY 6057212Sdab # include <stropts.h> 6157212Sdab # include <termio.h> 6257212Sdab /* make sure we don't get the bsd version */ 6357212Sdab # include "/usr/include/sys/tty.h" 6457212Sdab # include <sys/ptyvar.h> 6557212Sdab 666002Sroot /* 6757212Sdab * Because of the way ptyibuf is used with streams messages, we need 6857212Sdab * ptyibuf+1 to be on a full-word boundary. The following wierdness 6957212Sdab * is simply to make that happen. 7057212Sdab */ 7157212Sdab char ptyibufbuf[BUFSIZ+4]; 7257212Sdab char *ptyibuf = ptyibufbuf+3; 7357212Sdab char *ptyip = ptyibufbuf+3; 7457212Sdab char ptyibuf2[BUFSIZ]; 7557212Sdab unsigned char ctlbuf[BUFSIZ]; 7657212Sdab struct strbuf strbufc, strbufd; 7757212Sdab 7857212Sdab int readstream(); 7957212Sdab 8057212Sdab #else /* ! STREAMPTY */ 8157212Sdab 8257212Sdab /* 8338904Sborman * I/O data buffers, 8438904Sborman * pointers, and counters. 856002Sroot */ 8638904Sborman char ptyibuf[BUFSIZ], *ptyip = ptyibuf; 8738904Sborman char ptyibuf2[BUFSIZ]; 889218Ssam 8957212Sdab #endif /* ! STREAMPTY */ 9057212Sdab 9138904Sborman int hostinfo = 1; /* do we print login banner? */ 929218Ssam 9338904Sborman #ifdef CRAY 9438904Sborman extern int newmap; /* nonzero if \n maps to ^M^J */ 9540242Sborman int lowpty = 0, highpty; /* low, high pty numbers */ 9638904Sborman #endif /* CRAY */ 9712216Ssam 9838904Sborman int debug = 0; 9946809Sdab int keepalive = 1; 10038904Sborman char *progname; 1019218Ssam 10246809Sdab extern void usage P((void)); 10344363Sborman 10460151Sdab /* 10560151Sdab * The string to pass to getopt(). We do it this way so 10660151Sdab * that only the actual options that we support will be 10760151Sdab * passed off to getopt(). 10860151Sdab */ 10960151Sdab char valid_opts[] = { 11060151Sdab 'd', ':', 'h', 'k', 'n', 'S', ':', 'u', ':', 'U', 11160151Sdab #ifdef AUTHENTICATION 11260151Sdab 'a', ':', 'X', ':', 11360151Sdab #endif 11460151Sdab #ifdef BFTPDAEMON 11560151Sdab 'B', 11660151Sdab #endif 11760151Sdab #ifdef DIAGNOSTICS 11860151Sdab 'D', ':', 11960151Sdab #endif 12060151Sdab #ifdef ENCRYPTION 12160151Sdab 'e', ':', 12260151Sdab #endif 12360151Sdab #if defined(CRAY) && defined(NEWINIT) 12460151Sdab 'I', ':', 12560151Sdab #endif 12660151Sdab #ifdef LINEMODE 12760151Sdab 'l', 12860151Sdab #endif 12960151Sdab #ifdef CRAY 13060151Sdab 'r', ':', 13160151Sdab #endif 13260151Sdab #ifdef SecurID 13360151Sdab 's', 13460151Sdab #endif 13560151Sdab '\0' 13660151Sdab }; 13760151Sdab 13838904Sborman main(argc, argv) 13938904Sborman char *argv[]; 14038904Sborman { 14138904Sborman struct sockaddr_in from; 14238904Sborman int on = 1, fromlen; 14346809Sdab register int ch; 14446809Sdab extern char *optarg; 14546809Sdab extern int optind; 14646809Sdab #if defined(IPPROTO_IP) && defined(IP_TOS) 14746809Sdab int tos = -1; 14846809Sdab #endif 1496002Sroot 15038904Sborman pfrontp = pbackp = ptyobuf; 15138904Sborman netip = netibuf; 15238904Sborman nfrontp = nbackp = netobuf; 15360151Sdab #ifdef ENCRYPTION 15446809Sdab nclearto = 0; 15560151Sdab #endif /* ENCRYPTION */ 1566002Sroot 15738904Sborman progname = *argv; 15840242Sborman 15940242Sborman #ifdef CRAY 16040242Sborman /* 16140242Sborman * Get number of pty's before trying to process options, 16240242Sborman * which may include changing pty range. 16340242Sborman */ 16440242Sborman highpty = getnpty(); 16540242Sborman #endif /* CRAY */ 16640242Sborman 16760151Sdab while ((ch = getopt(argc, argv, valid_opts)) != EOF) { 16846809Sdab switch(ch) { 16927649Sminshall 17057212Sdab #ifdef AUTHENTICATION 17146809Sdab case 'a': 17246809Sdab /* 17346809Sdab * Check for required authentication level 17446809Sdab */ 17546809Sdab if (strcmp(optarg, "debug") == 0) { 17646809Sdab extern int auth_debug_mode; 17746809Sdab auth_debug_mode = 1; 17846809Sdab } else if (strcasecmp(optarg, "none") == 0) { 17946809Sdab auth_level = 0; 18046809Sdab } else if (strcasecmp(optarg, "other") == 0) { 18146809Sdab auth_level = AUTH_OTHER; 18246809Sdab } else if (strcasecmp(optarg, "user") == 0) { 18346809Sdab auth_level = AUTH_USER; 18446809Sdab } else if (strcasecmp(optarg, "valid") == 0) { 18546809Sdab auth_level = AUTH_VALID; 18646809Sdab } else if (strcasecmp(optarg, "off") == 0) { 18746809Sdab /* 18846809Sdab * This hack turns off authentication 18946809Sdab */ 19046809Sdab auth_level = -1; 19146809Sdab } else { 19246809Sdab fprintf(stderr, 19346809Sdab "telnetd: unknown authorization level for -a\n"); 19446809Sdab } 19546809Sdab break; 19657212Sdab #endif /* AUTHENTICATION */ 19727649Sminshall 19846809Sdab #ifdef BFTPDAEMON 19946809Sdab case 'B': 20046809Sdab bftpd++; 20146809Sdab break; 20246809Sdab #endif /* BFTPDAEMON */ 20346809Sdab 20446809Sdab case 'd': 20546809Sdab if (strcmp(optarg, "ebug") == 0) { 20646809Sdab debug++; 20746809Sdab break; 20846809Sdab } 20946809Sdab usage(); 21046809Sdab /* NOTREACHED */ 21146809Sdab break; 21246809Sdab 21346809Sdab #ifdef DIAGNOSTICS 21446809Sdab case 'D': 21546809Sdab /* 21646809Sdab * Check for desired diagnostics capabilities. 21746809Sdab */ 21846809Sdab if (!strcmp(optarg, "report")) { 21946809Sdab diagnostic |= TD_REPORT|TD_OPTIONS; 22046809Sdab } else if (!strcmp(optarg, "exercise")) { 22146809Sdab diagnostic |= TD_EXERCISE; 22246809Sdab } else if (!strcmp(optarg, "netdata")) { 22346809Sdab diagnostic |= TD_NETDATA; 22446809Sdab } else if (!strcmp(optarg, "ptydata")) { 22546809Sdab diagnostic |= TD_PTYDATA; 22646809Sdab } else if (!strcmp(optarg, "options")) { 22746809Sdab diagnostic |= TD_OPTIONS; 22846809Sdab } else { 22946809Sdab usage(); 23046809Sdab /* NOT REACHED */ 23146809Sdab } 23246809Sdab break; 23346809Sdab #endif /* DIAGNOSTICS */ 23446809Sdab 23557212Sdab #ifdef ENCRYPTION 23646809Sdab case 'e': 23746809Sdab if (strcmp(optarg, "debug") == 0) { 23846809Sdab extern int encrypt_debug_mode; 23946809Sdab encrypt_debug_mode = 1; 24046809Sdab break; 24146809Sdab } 24246809Sdab usage(); 24346809Sdab /* NOTREACHED */ 24446809Sdab break; 24557212Sdab #endif /* ENCRYPTION */ 24646809Sdab 24746809Sdab case 'h': 24846809Sdab hostinfo = 0; 24946809Sdab break; 25046809Sdab 25146809Sdab #if defined(CRAY) && defined(NEWINIT) 25246809Sdab case 'I': 25346809Sdab { 25446809Sdab extern char *gen_id; 25546809Sdab gen_id = optarg; 25646809Sdab break; 25746809Sdab } 25846809Sdab #endif /* defined(CRAY) && defined(NEWINIT) */ 25946809Sdab 26038904Sborman #ifdef LINEMODE 26146809Sdab case 'l': 26246809Sdab alwayslinemode = 1; 26346809Sdab break; 26438904Sborman #endif /* LINEMODE */ 26527649Sminshall 26657212Sdab case 'k': 26757212Sdab #if defined(LINEMODE) && defined(KLUDGELINEMODE) 26857212Sdab lmodetype = NO_AUTOKLUDGE; 26957212Sdab #else 27057212Sdab /* ignore -k option if built without kludge linemode */ 27157212Sdab #endif /* defined(LINEMODE) && defined(KLUDGELINEMODE) */ 27257212Sdab break; 27357212Sdab 27446809Sdab case 'n': 27546809Sdab keepalive = 0; 27646809Sdab break; 27727649Sminshall 27845234Sborman #ifdef CRAY 27946809Sdab case 'r': 28046809Sdab { 28146809Sdab char *strchr(); 28246809Sdab char *c; 28327649Sminshall 28446809Sdab /* 28546809Sdab * Allow the specification of alterations 28646809Sdab * to the pty search range. It is legal to 28746809Sdab * specify only one, and not change the 28846809Sdab * other from its default. 28946809Sdab */ 29046809Sdab c = strchr(optarg, '-'); 29146809Sdab if (c) { 29246809Sdab *c++ = '\0'; 29346809Sdab highpty = atoi(c); 29444363Sborman } 29546809Sdab if (*optarg != '\0') 29646809Sdab lowpty = atoi(optarg); 29746809Sdab if ((lowpty > highpty) || (lowpty < 0) || 29846809Sdab (highpty > 32767)) { 29944363Sborman usage(); 30044363Sborman /* NOT REACHED */ 30144363Sborman } 30246809Sdab break; 30346809Sdab } 30438904Sborman #endif /* CRAY */ 3056002Sroot 30646809Sdab #ifdef SecurID 30746809Sdab case 's': 30846809Sdab /* SecurID required */ 30946809Sdab require_SecurID = 1; 31046809Sdab break; 31146809Sdab #endif /* SecurID */ 31246809Sdab case 'S': 31346809Sdab #ifdef HAS_GETTOS 31446809Sdab if ((tos = parsetos(optarg, "tcp")) < 0) 31546809Sdab fprintf(stderr, "%s%s%s\n", 31646809Sdab "telnetd: Bad TOS argument '", optarg, 31746809Sdab "'; will try to use default TOS"); 31846809Sdab #else 31946809Sdab fprintf(stderr, "%s%s\n", "TOS option unavailable; ", 32046809Sdab "-S flag not supported\n"); 32146809Sdab #endif 32246809Sdab break; 32346809Sdab 32457212Sdab case 'u': 32557212Sdab utmp_len = atoi(optarg); 32657212Sdab break; 32757212Sdab 32857212Sdab case 'U': 32957212Sdab registerd_host_only = 1; 33057212Sdab break; 33157212Sdab 33257212Sdab #ifdef AUTHENTICATION 33346809Sdab case 'X': 33446809Sdab /* 33546809Sdab * Check for invalid authentication types 33646809Sdab */ 33746809Sdab auth_disable_name(optarg); 33846809Sdab break; 33957212Sdab #endif /* AUTHENTICATION */ 34046809Sdab 34146809Sdab default: 34260151Sdab fprintf(stderr, "telnetd: %c: unknown option\n", ch); 34346809Sdab /* FALLTHROUGH */ 34446809Sdab case '?': 34544363Sborman usage(); 34646809Sdab /* NOTREACHED */ 34744363Sborman } 34844363Sborman } 34944363Sborman 35046809Sdab argc -= optind; 35146809Sdab argv += optind; 35244363Sborman 35338904Sborman if (debug) { 35427185Sminshall int s, ns, foo; 35527185Sminshall struct servent *sp; 35627185Sminshall static struct sockaddr_in sin = { AF_INET }; 35727185Sminshall 35844363Sborman if (argc > 1) { 35944363Sborman usage(); 36044363Sborman /* NOT REACHED */ 36144363Sborman } else if (argc == 1) { 36238904Sborman if (sp = getservbyname(*argv, "tcp")) { 36338904Sborman sin.sin_port = sp->s_port; 36438904Sborman } else { 36538904Sborman sin.sin_port = atoi(*argv); 36638904Sborman if ((int)sin.sin_port <= 0) { 36738904Sborman fprintf(stderr, "telnetd: %s: bad port #\n", *argv); 36844363Sborman usage(); 36944363Sborman /* NOT REACHED */ 37038904Sborman } 37138904Sborman sin.sin_port = htons((u_short)sin.sin_port); 37238904Sborman } 37337210Sminshall } else { 37437210Sminshall sp = getservbyname("telnet", "tcp"); 37537210Sminshall if (sp == 0) { 37644363Sborman fprintf(stderr, "telnetd: tcp/telnet: unknown service\n"); 37738904Sborman exit(1); 37837210Sminshall } 37937210Sminshall sin.sin_port = sp->s_port; 38027185Sminshall } 38127185Sminshall 38227185Sminshall s = socket(AF_INET, SOCK_STREAM, 0); 38327185Sminshall if (s < 0) { 38427185Sminshall perror("telnetd: socket");; 38527185Sminshall exit(1); 38627185Sminshall } 38757212Sdab (void) setsockopt(s, SOL_SOCKET, SO_REUSEADDR, 38857212Sdab (char *)&on, sizeof(on)); 38938904Sborman if (bind(s, (struct sockaddr *)&sin, sizeof sin) < 0) { 39027185Sminshall perror("bind"); 39127185Sminshall exit(1); 39227185Sminshall } 39327185Sminshall if (listen(s, 1) < 0) { 39427185Sminshall perror("listen"); 39527185Sminshall exit(1); 39627185Sminshall } 39727185Sminshall foo = sizeof sin; 39838904Sborman ns = accept(s, (struct sockaddr *)&sin, &foo); 39927185Sminshall if (ns < 0) { 40027185Sminshall perror("accept"); 40127185Sminshall exit(1); 40227185Sminshall } 40338904Sborman (void) dup2(ns, 0); 40438904Sborman (void) close(ns); 40538904Sborman (void) close(s); 40646809Sdab #ifdef convex 40746809Sdab } else if (argc == 1) { 40846809Sdab ; /* VOID*/ /* Just ignore the host/port name */ 40946809Sdab #endif 41044363Sborman } else if (argc > 0) { 41144363Sborman usage(); 41244363Sborman /* NOT REACHED */ 41327185Sminshall } 41438904Sborman 41557212Sdab #if defined(_SC_CRAY_SECURE_SYS) 41657212Sdab secflag = sysconf(_SC_CRAY_SECURE_SYS); 41757212Sdab 41857212Sdab /* 41960151Sdab * Get socket's security label 42057212Sdab */ 42157212Sdab if (secflag) { 42260151Sdab int szss = sizeof(ss); 42360151Sdab #ifdef SO_SEC_MULTI /* 8.0 code */ 42460151Sdab int sock_multi; 42560151Sdab int szi = sizeof(int); 42660151Sdab #endif /* SO_SEC_MULTI */ 42757212Sdab 42857212Sdab bzero((char *)&dv, sizeof(dv)); 42957212Sdab 43057212Sdab if (getsysv(&sysv, sizeof(struct sysv)) != 0) { 43157212Sdab perror("getsysv"); 43257212Sdab exit(1); 43357212Sdab } 43457212Sdab 43557212Sdab /* 43660151Sdab * Get socket security label and set device values 43760151Sdab * {security label to be set on ttyp device} 43857212Sdab */ 43960151Sdab #ifdef SO_SEC_MULTI /* 8.0 code */ 44060151Sdab if ((getsockopt(0, SOL_SOCKET, SO_SECURITY, 44160151Sdab (char *)&ss, &szss) < 0) || 44260151Sdab (getsockopt(0, SOL_SOCKET, SO_SEC_MULTI, 44360151Sdab (char *)&sock_multi, &szi) < 0)) { 44460151Sdab perror("getsockopt"); 44560151Sdab exit(1); 44660151Sdab } else { 44760151Sdab dv.dv_actlvl = ss.ss_actlabel.lt_level; 44860151Sdab dv.dv_actcmp = ss.ss_actlabel.lt_compart; 44960151Sdab if (!sock_multi) { 45060151Sdab dv.dv_minlvl = dv.dv_maxlvl = dv.dv_actlvl; 45160151Sdab dv.dv_valcmp = dv.dv_actcmp; 45260151Sdab } else { 45360151Sdab dv.dv_minlvl = ss.ss_minlabel.lt_level; 45460151Sdab dv.dv_maxlvl = ss.ss_maxlabel.lt_level; 45560151Sdab dv.dv_valcmp = ss.ss_maxlabel.lt_compart; 45660151Sdab } 45760151Sdab dv.dv_devflg = 0; 45860151Sdab } 45960151Sdab #else /* SO_SEC_MULTI */ /* 7.0 code */ 46057212Sdab if (getsockopt(0, SOL_SOCKET, SO_SECURITY, 46160151Sdab (char *)&ss, &szss) >= 0) { 46257212Sdab dv.dv_actlvl = ss.ss_slevel; 46357212Sdab dv.dv_actcmp = ss.ss_compart; 46457212Sdab dv.dv_minlvl = ss.ss_minlvl; 46557212Sdab dv.dv_maxlvl = ss.ss_maxlvl; 46657212Sdab dv.dv_valcmp = ss.ss_maxcmp; 46757212Sdab } 46860151Sdab #endif /* SO_SEC_MULTI */ 46957212Sdab } 47057212Sdab #endif /* _SC_CRAY_SECURE_SYS */ 47157212Sdab 47224855Seric openlog("telnetd", LOG_PID | LOG_ODELAY, LOG_DAEMON); 47316371Skarels fromlen = sizeof (from); 47438904Sborman if (getpeername(0, (struct sockaddr *)&from, &fromlen) < 0) { 47538904Sborman fprintf(stderr, "%s: ", progname); 47616371Skarels perror("getpeername"); 47716371Skarels _exit(1); 4788346Ssam } 47946809Sdab if (keepalive && 48057212Sdab setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, 48157212Sdab (char *)&on, sizeof (on)) < 0) { 48217187Sralph syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m"); 48310418Ssam } 48440242Sborman 48546809Sdab #if defined(IPPROTO_IP) && defined(IP_TOS) 48646809Sdab { 48746809Sdab # if defined(HAS_GETTOS) 48846809Sdab struct tosent *tp; 48946809Sdab if (tos < 0 && (tp = gettosbyname("telnet", "tcp"))) 49046809Sdab tos = tp->t_tos; 49146809Sdab # endif 49246809Sdab if (tos < 0) 49346809Sdab tos = 020; /* Low Delay bit */ 49446809Sdab if (tos 49557212Sdab && (setsockopt(0, IPPROTO_IP, IP_TOS, 49657212Sdab (char *)&tos, sizeof(tos)) < 0) 49746809Sdab && (errno != ENOPROTOOPT) ) 49846809Sdab syslog(LOG_WARNING, "setsockopt (IP_TOS): %m"); 49946809Sdab } 50046809Sdab #endif /* defined(IPPROTO_IP) && defined(IP_TOS) */ 50138904Sborman net = 0; 50238904Sborman doit(&from); 50338904Sborman /* NOTREACHED */ 50438904Sborman } /* end of main */ 5056002Sroot 50646809Sdab void 50744363Sborman usage() 50844363Sborman { 50946809Sdab fprintf(stderr, "Usage: telnetd"); 51057212Sdab #ifdef AUTHENTICATION 51160151Sdab fprintf(stderr, " [-a (debug|other|user|valid|off|none)]\n\t"); 51246809Sdab #endif 51346809Sdab #ifdef BFTPDAEMON 51446809Sdab fprintf(stderr, " [-B]"); 51546809Sdab #endif 51646809Sdab fprintf(stderr, " [-debug]"); 51746809Sdab #ifdef DIAGNOSTICS 51846809Sdab fprintf(stderr, " [-D (options|report|exercise|netdata|ptydata)]\n\t"); 51946809Sdab #endif 52057212Sdab #ifdef AUTHENTICATION 52146809Sdab fprintf(stderr, " [-edebug]"); 52246809Sdab #endif 52346809Sdab fprintf(stderr, " [-h]"); 52446809Sdab #if defined(CRAY) && defined(NEWINIT) 52544363Sborman fprintf(stderr, " [-Iinitid]"); 52646809Sdab #endif 52760151Sdab #if defined(LINEMODE) && defined(KLUDGELINEMODE) 52860151Sdab fprintf(stderr, " [-k]"); 52960151Sdab #endif 53044363Sborman #ifdef LINEMODE 53144363Sborman fprintf(stderr, " [-l]"); 53244363Sborman #endif 53346809Sdab fprintf(stderr, " [-n]"); 53444363Sborman #ifdef CRAY 53544363Sborman fprintf(stderr, " [-r[lowpty]-[highpty]]"); 53644363Sborman #endif 53760151Sdab fprintf(stderr, "\n\t"); 53846809Sdab #ifdef SecurID 53946809Sdab fprintf(stderr, " [-s]"); 54046809Sdab #endif 54160151Sdab #ifdef HAS_GETTOS 54260151Sdab fprintf(stderr, " [-S tos]"); 54360151Sdab #endif 54457212Sdab #ifdef AUTHENTICATION 54546809Sdab fprintf(stderr, " [-X auth-type]"); 54646809Sdab #endif 54757212Sdab fprintf(stderr, " [-u utmp_hostname_length] [-U]"); 54844363Sborman fprintf(stderr, " [port]\n"); 54944363Sborman exit(1); 55044363Sborman } 55144363Sborman 55227649Sminshall /* 55327983Sminshall * getterminaltype 55427649Sminshall * 55538904Sborman * Ask the other end to send along its terminal type and speed. 55627983Sminshall * Output is the variable terminaltype filled in. 55727649Sminshall */ 55838904Sborman static char ttytype_sbbuf[] = { IAC, SB, TELOPT_TTYPE, TELQUAL_SEND, IAC, SE }; 55946809Sdab 56046809Sdab int 56146809Sdab getterminaltype(name) 56246809Sdab char *name; 56327649Sminshall { 56446809Sdab int retval = -1; 56546809Sdab void _gettermname(); 56627649Sminshall 56738904Sborman settimer(baseline); 56857212Sdab #if defined(AUTHENTICATION) 56946809Sdab /* 57046809Sdab * Handle the Authentication option before we do anything else. 57146809Sdab */ 57246809Sdab send_do(TELOPT_AUTHENTICATION, 1); 57346809Sdab while (his_will_wont_is_changing(TELOPT_AUTHENTICATION)) 57446809Sdab ttloop(); 57546809Sdab if (his_state_is_will(TELOPT_AUTHENTICATION)) { 57646809Sdab retval = auth_wait(name); 57746809Sdab } 57846809Sdab #endif 57946809Sdab 58060151Sdab #ifdef ENCRYPTION 58146809Sdab send_will(TELOPT_ENCRYPT, 1); 58260151Sdab #endif /* ENCRYPTION */ 58339503Sborman send_do(TELOPT_TTYPE, 1); 58439503Sborman send_do(TELOPT_TSPEED, 1); 58544363Sborman send_do(TELOPT_XDISPLOC, 1); 58644363Sborman send_do(TELOPT_ENVIRON, 1); 58746809Sdab while ( 58860151Sdab #ifdef ENCRYPTION 58946809Sdab his_do_dont_is_changing(TELOPT_ENCRYPT) || 59060151Sdab #endif /* ENCRYPTION */ 59146809Sdab his_will_wont_is_changing(TELOPT_TTYPE) || 59244363Sborman his_will_wont_is_changing(TELOPT_TSPEED) || 59344363Sborman his_will_wont_is_changing(TELOPT_XDISPLOC) || 59444363Sborman his_will_wont_is_changing(TELOPT_ENVIRON)) { 59527983Sminshall ttloop(); 59627649Sminshall } 59760151Sdab #ifdef ENCRYPTION 59846809Sdab /* 59946809Sdab * Wait for the negotiation of what type of encryption we can 60046809Sdab * send with. If autoencrypt is not set, this will just return. 60146809Sdab */ 60246809Sdab if (his_state_is_will(TELOPT_ENCRYPT)) { 60346809Sdab encrypt_wait(); 60446809Sdab } 60560151Sdab #endif /* ENCRYPTION */ 60644363Sborman if (his_state_is_will(TELOPT_TSPEED)) { 60738904Sborman static char sbbuf[] = { IAC, SB, TELOPT_TSPEED, TELQUAL_SEND, IAC, SE }; 60827983Sminshall 60927983Sminshall bcopy(sbbuf, nfrontp, sizeof sbbuf); 61027983Sminshall nfrontp += sizeof sbbuf; 61138904Sborman } 61244363Sborman if (his_state_is_will(TELOPT_XDISPLOC)) { 61344363Sborman static char sbbuf[] = { IAC, SB, TELOPT_XDISPLOC, TELQUAL_SEND, IAC, SE }; 61438904Sborman 61544363Sborman bcopy(sbbuf, nfrontp, sizeof sbbuf); 61644363Sborman nfrontp += sizeof sbbuf; 61744363Sborman } 61844363Sborman if (his_state_is_will(TELOPT_ENVIRON)) { 61944363Sborman static char sbbuf[] = { IAC, SB, TELOPT_ENVIRON, TELQUAL_SEND, IAC, SE }; 62044363Sborman 62144363Sborman bcopy(sbbuf, nfrontp, sizeof sbbuf); 62244363Sborman nfrontp += sizeof sbbuf; 62344363Sborman } 62444363Sborman if (his_state_is_will(TELOPT_TTYPE)) { 62544363Sborman 62638904Sborman bcopy(ttytype_sbbuf, nfrontp, sizeof ttytype_sbbuf); 62738904Sborman nfrontp += sizeof ttytype_sbbuf; 62838904Sborman } 62944363Sborman if (his_state_is_will(TELOPT_TSPEED)) { 63038904Sborman while (sequenceIs(tspeedsubopt, baseline)) 63127983Sminshall ttloop(); 63238904Sborman } 63344363Sborman if (his_state_is_will(TELOPT_XDISPLOC)) { 63444363Sborman while (sequenceIs(xdisplocsubopt, baseline)) 63544363Sborman ttloop(); 63644363Sborman } 63744363Sborman if (his_state_is_will(TELOPT_ENVIRON)) { 63844363Sborman while (sequenceIs(environsubopt, baseline)) 63944363Sborman ttloop(); 64044363Sborman } 64144363Sborman if (his_state_is_will(TELOPT_TTYPE)) { 64238904Sborman char first[256], last[256]; 64338904Sborman 64438904Sborman while (sequenceIs(ttypesubopt, baseline)) 64538904Sborman ttloop(); 64638904Sborman 64744363Sborman /* 64844363Sborman * If the other side has already disabled the option, then 64944363Sborman * we have to just go with what we (might) have already gotten. 65044363Sborman */ 65144363Sborman if (his_state_is_will(TELOPT_TTYPE) && !terminaltypeok(terminaltype)) { 65238904Sborman (void) strncpy(first, terminaltype, sizeof(first)); 65338904Sborman for(;;) { 65438904Sborman /* 65538904Sborman * Save the unknown name, and request the next name. 65638904Sborman */ 65738904Sborman (void) strncpy(last, terminaltype, sizeof(last)); 65838904Sborman _gettermname(); 65944363Sborman if (terminaltypeok(terminaltype)) 66038904Sborman break; 66144363Sborman if ((strncmp(last, terminaltype, sizeof(last)) == 0) || 66244363Sborman his_state_is_wont(TELOPT_TTYPE)) { 66338904Sborman /* 66438904Sborman * We've hit the end. If this is the same as 66538904Sborman * the first name, just go with it. 66638904Sborman */ 66745234Sborman if (strncmp(first, terminaltype, sizeof(first)) == 0) 66838904Sborman break; 66938904Sborman /* 67044363Sborman * Get the terminal name one more time, so that 67138904Sborman * RFC1091 compliant telnets will cycle back to 67238904Sborman * the start of the list. 67338904Sborman */ 67444363Sborman _gettermname(); 67545234Sborman if (strncmp(first, terminaltype, sizeof(first)) != 0) 67638904Sborman (void) strncpy(terminaltype, first, sizeof(first)); 67738904Sborman break; 67838904Sborman } 67938904Sborman } 68027983Sminshall } 68127983Sminshall } 68246809Sdab return(retval); 68338904Sborman } /* end of getterminaltype */ 68438904Sborman 68546809Sdab void 68638904Sborman _gettermname() 68738904Sborman { 68844363Sborman /* 68944363Sborman * If the client turned off the option, 69044363Sborman * we can't send another request, so we 69144363Sborman * just return. 69244363Sborman */ 69344363Sborman if (his_state_is_wont(TELOPT_TTYPE)) 69444363Sborman return; 69538904Sborman settimer(baseline); 69638904Sborman bcopy(ttytype_sbbuf, nfrontp, sizeof ttytype_sbbuf); 69738904Sborman nfrontp += sizeof ttytype_sbbuf; 69838904Sborman while (sequenceIs(ttypesubopt, baseline)) 69938904Sborman ttloop(); 70027649Sminshall } 70127649Sminshall 70246809Sdab int 70338904Sborman terminaltypeok(s) 70446809Sdab char *s; 70538904Sborman { 70638904Sborman char buf[1024]; 70738904Sborman 70838904Sborman if (terminaltype == NULL) 70938904Sborman return(1); 71038904Sborman 71138904Sborman /* 71238904Sborman * tgetent() will return 1 if the type is known, and 71338904Sborman * 0 if it is not known. If it returns -1, it couldn't 71438904Sborman * open the database. But if we can't open the database, 71538904Sborman * it won't help to say we failed, because we won't be 71638904Sborman * able to verify anything else. So, we treat -1 like 1. 71738904Sborman */ 71838904Sborman if (tgetent(buf, s) == 0) 71938904Sborman return(0); 72038904Sborman return(1); 72138904Sborman } 72238904Sborman 72346809Sdab #ifndef MAXHOSTNAMELEN 72446809Sdab #define MAXHOSTNAMELEN 64 72546809Sdab #endif /* MAXHOSTNAMELEN */ 72646809Sdab 72746809Sdab char *hostname; 72846809Sdab char host_name[MAXHOSTNAMELEN]; 72946809Sdab char remote_host_name[MAXHOSTNAMELEN]; 73046809Sdab 73146809Sdab #ifndef convex 73246809Sdab extern void telnet P((int, int)); 73346809Sdab #else 73446809Sdab extern void telnet P((int, int, char *)); 73546809Sdab #endif 73646809Sdab 7376002Sroot /* 7386002Sroot * Get a pty, scan input lines. 7396002Sroot */ 74038904Sborman doit(who) 74112683Ssam struct sockaddr_in *who; 7426002Sroot { 74320188Skarels char *host, *inet_ntoa(); 74438904Sborman int t; 74512683Ssam struct hostent *hp; 74646809Sdab int level; 74760151Sdab int ptynum; 74846809Sdab char user_name[256]; 7496002Sroot 75038904Sborman /* 75138904Sborman * Find an available pty to use. 75238904Sborman */ 75345234Sborman #ifndef convex 75460151Sdab pty = getpty(&ptynum); 75538904Sborman if (pty < 0) 75638904Sborman fatal(net, "All network ports in use"); 75745234Sborman #else 75845234Sborman for (;;) { 75945234Sborman char *lp; 76045234Sborman extern char *line, *getpty(); 76120188Skarels 76245234Sborman if ((lp = getpty()) == NULL) 76345234Sborman fatal(net, "Out of ptys"); 76445234Sborman 76545234Sborman if ((pty = open(lp, 2)) >= 0) { 76645234Sborman strcpy(line,lp); 76745234Sborman line[5] = 't'; 76845234Sborman break; 76945234Sborman } 77045234Sborman } 77144545Smarc #endif 77238904Sborman 77357212Sdab #if defined(_SC_CRAY_SECURE_SYS) 77457212Sdab /* 77557212Sdab * set ttyp line security label 77657212Sdab */ 77757212Sdab if (secflag) { 77860151Sdab char slave_dev[16]; 77960151Sdab 78060151Sdab sprintf(tty_dev, "/dev/pty/%03d", ptynum); 78160151Sdab if (setdevs(tty_dev, &dv) < 0) 78260151Sdab fatal(net, "cannot set pty security"); 78360151Sdab sprintf(slave_dev, "/dev/ttyp%03d", ptynum); 78460151Sdab if (setdevs(slave_dev, &dv) < 0) 78560151Sdab fatal(net, "cannot set tty security"); 78657212Sdab } 78757212Sdab #endif /* _SC_CRAY_SECURE_SYS */ 78857212Sdab 78938904Sborman /* get name of connected client */ 79038904Sborman hp = gethostbyaddr((char *)&who->sin_addr, sizeof (struct in_addr), 79112683Ssam who->sin_family); 79257212Sdab 79357641Sdab if (hp == NULL && registerd_host_only) { 79457641Sdab fatal(net, "Couldn't resolve your address into a host name.\r\n\ 79557641Sdab Please contact your net administrator"); 79657641Sdab } else if (hp && 79757212Sdab (strlen(hp->h_name) <= ((utmp_len < 0) ? -utmp_len : utmp_len))) { 79812683Ssam host = hp->h_name; 79957212Sdab } else { 80017444Sralph host = inet_ntoa(who->sin_addr); 80157212Sdab } 80246809Sdab /* 80346809Sdab * We must make a copy because Kerberos is probably going 80446809Sdab * to also do a gethost* and overwrite the static data... 80546809Sdab */ 80646809Sdab strncpy(remote_host_name, host, sizeof(remote_host_name)-1); 80746809Sdab remote_host_name[sizeof(remote_host_name)-1] = 0; 80846809Sdab host = remote_host_name; 80927983Sminshall 81046809Sdab (void) gethostname(host_name, sizeof (host_name)); 81146809Sdab hostname = host_name; 81246809Sdab 81357212Sdab #if defined(AUTHENTICATION) || defined(ENCRYPTION) 81446809Sdab auth_encrypt_init(hostname, host, "TELNETD", 1); 81546809Sdab #endif 81646809Sdab 81744363Sborman init_env(); 81827983Sminshall /* 81938904Sborman * get terminal type. 82027983Sminshall */ 82146809Sdab *user_name = 0; 82246809Sdab level = getterminaltype(user_name); 82344363Sborman setenv("TERM", terminaltype ? terminaltype : "network", 1); 82427983Sminshall 82527649Sminshall /* 82638904Sborman * Start up the login process on the slave side of the terminal 82727649Sminshall */ 82845234Sborman #ifndef convex 82946809Sdab startslave(host, level, user_name); 83038904Sborman 83160151Sdab #if defined(_SC_CRAY_SECURE_SYS) 83260151Sdab if (secflag) { 83360151Sdab if (setulvl(dv.dv_actlvl) < 0) 83460151Sdab fatal(net,"cannot setulvl()"); 83560151Sdab if (setucmp(dv.dv_actcmp) < 0) 83660151Sdab fatal(net, "cannot setucmp()"); 83760151Sdab } 83860151Sdab #endif /* _SC_CRAY_SECURE_SYS */ 83960151Sdab 84038904Sborman telnet(net, pty); /* begin server processing */ 84145234Sborman #else 84245234Sborman telnet(net, pty, host); 84345234Sborman #endif 8449244Ssam /*NOTREACHED*/ 84538904Sborman } /* end of doit */ 8469244Ssam 84746809Sdab #if defined(CRAY2) && defined(UNICOS5) && defined(UNICOS50) 84846809Sdab int 84946809Sdab Xterm_output(ibufp, obuf, icountp, ocount) 85046809Sdab char **ibufp, *obuf; 85146809Sdab int *icountp, ocount; 85246809Sdab { 85346809Sdab int ret; 85446809Sdab ret = term_output(*ibufp, obuf, *icountp, ocount); 85546809Sdab *ibufp += *icountp; 85646809Sdab *icountp = 0; 85746809Sdab return(ret); 85846809Sdab } 85946809Sdab #define term_output Xterm_output 86046809Sdab #endif /* defined(CRAY2) && defined(UNICOS5) && defined(UNICOS50) */ 86146809Sdab 8626002Sroot /* 8636002Sroot * Main loop. Select from pty and network, and 8646002Sroot * hand data to telnet receiver finite state machine. 8656002Sroot */ 86646809Sdab void 86745234Sborman #ifndef convex 8686002Sroot telnet(f, p) 86945234Sborman #else 87045234Sborman telnet(f, p, host) 87145234Sborman #endif 87246809Sdab int f, p; 87345234Sborman #ifdef convex 87446809Sdab char *host; 87545234Sborman #endif 8766002Sroot { 8776002Sroot int on = 1; 87833271Sminshall #define TABBUFSIZ 512 87933271Sminshall char defent[TABBUFSIZ]; 88033271Sminshall char defstrs[TABBUFSIZ]; 88133271Sminshall #undef TABBUFSIZ 88233271Sminshall char *HE; 88333271Sminshall char *HN; 88433271Sminshall char *IM; 88538904Sborman void netflush(); 88646809Sdab 88732400Sminshall /* 88838904Sborman * Initialize the slc mapping table. 88932400Sminshall */ 89038904Sborman get_slc_defaults(); 8916002Sroot 8928379Ssam /* 89338904Sborman * Do some tests where it is desireable to wait for a response. 89438904Sborman * Rather than doing them slowly, one at a time, do them all 89538904Sborman * at once. 8968379Ssam */ 89744363Sborman if (my_state_is_wont(TELOPT_SGA)) 89839503Sborman send_will(TELOPT_SGA, 1); 89912713Ssam /* 90027649Sminshall * Is the client side a 4.2 (NOT 4.3) system? We need to know this 90127649Sminshall * because 4.2 clients are unable to deal with TCP urgent data. 90227649Sminshall * 90327649Sminshall * To find out, we send out a "DO ECHO". If the remote system 90427649Sminshall * answers "WILL ECHO" it is probably a 4.2 client, and we note 90527649Sminshall * that fact ("WILL ECHO" ==> that the client will echo what 90627649Sminshall * WE, the server, sends it; it does NOT mean that the client will 90727649Sminshall * echo the terminal input). 90827649Sminshall */ 90939503Sborman send_do(TELOPT_ECHO, 1); 91027649Sminshall 91138904Sborman #ifdef LINEMODE 91244363Sborman if (his_state_is_wont(TELOPT_LINEMODE)) { 91338904Sborman /* Query the peer for linemode support by trying to negotiate 91438904Sborman * the linemode option. 91538904Sborman */ 91644363Sborman linemode = 0; 91738904Sborman editmode = 0; 91839503Sborman send_do(TELOPT_LINEMODE, 1); /* send do linemode */ 91938904Sborman } 92038904Sborman #endif /* LINEMODE */ 92138904Sborman 92227649Sminshall /* 92338904Sborman * Send along a couple of other options that we wish to negotiate. 92438904Sborman */ 92539503Sborman send_do(TELOPT_NAWS, 1); 92639503Sborman send_will(TELOPT_STATUS, 1); 92757597Sdab flowmode = 1; /* default flow control state */ 92857597Sdab restartany = -1; /* uninitialized... */ 92939503Sborman send_do(TELOPT_LFLOW, 1); 93038904Sborman 93138904Sborman /* 93238904Sborman * Spin, waiting for a response from the DO ECHO. However, 93338904Sborman * some REALLY DUMB telnets out there might not respond 93438904Sborman * to the DO ECHO. So, we spin looking for NAWS, (most dumb 93538904Sborman * telnets so far seem to respond with WONT for a DO that 93638904Sborman * they don't understand...) because by the time we get the 93738904Sborman * response, it will already have processed the DO ECHO. 93838904Sborman * Kludge upon kludge. 93938904Sborman */ 94044363Sborman while (his_will_wont_is_changing(TELOPT_NAWS)) 94138904Sborman ttloop(); 94238904Sborman 94338904Sborman /* 94444363Sborman * But... 94544363Sborman * The client might have sent a WILL NAWS as part of its 94644363Sborman * startup code; if so, we'll be here before we get the 94744363Sborman * response to the DO ECHO. We'll make the assumption 94844363Sborman * that any implementation that understands about NAWS 94944363Sborman * is a modern enough implementation that it will respond 95044363Sborman * to our DO ECHO request; hence we'll do another spin 95144363Sborman * waiting for the ECHO option to settle down, which is 95244363Sborman * what we wanted to do in the first place... 95344363Sborman */ 95444363Sborman if (his_want_state_is_will(TELOPT_ECHO) && 95544363Sborman his_state_is_will(TELOPT_NAWS)) { 95644363Sborman while (his_will_wont_is_changing(TELOPT_ECHO)) 95744363Sborman ttloop(); 95844363Sborman } 95944363Sborman /* 96038995Sborman * On the off chance that the telnet client is broken and does not 96138995Sborman * respond to the DO ECHO we sent, (after all, we did send the 96238995Sborman * DO NAWS negotiation after the DO ECHO, and we won't get here 96338995Sborman * until a response to the DO NAWS comes back) simulate the 96438995Sborman * receipt of a will echo. This will also send a WONT ECHO 96538995Sborman * to the client, since we assume that the client failed to 96638995Sborman * respond because it believes that it is already in DO ECHO 96738995Sborman * mode, which we do not want. 96838995Sborman */ 96944363Sborman if (his_want_state_is_will(TELOPT_ECHO)) { 97046809Sdab DIAG(TD_OPTIONS, 97146809Sdab {sprintf(nfrontp, "td: simulating recv\r\n"); 97246809Sdab nfrontp += strlen(nfrontp);}); 97339503Sborman willoption(TELOPT_ECHO); 97440242Sborman } 97538995Sborman 97638995Sborman /* 97738995Sborman * Finally, to clean things up, we turn on our echo. This 97838995Sborman * will break stupid 4.2 telnets out of local terminal echo. 97938995Sborman */ 98038995Sborman 98144363Sborman if (my_state_is_wont(TELOPT_ECHO)) 98239503Sborman send_will(TELOPT_ECHO, 1); 98338995Sborman 98457212Sdab #ifndef STREAMSPTY 98538995Sborman /* 98645234Sborman * Turn on packet mode 98738904Sborman */ 98838904Sborman (void) ioctl(p, TIOCPKT, (char *)&on); 98957212Sdab #endif 99057212Sdab 99146809Sdab #if defined(LINEMODE) && defined(KLUDGELINEMODE) 99238904Sborman /* 99338904Sborman * Continuing line mode support. If client does not support 99438904Sborman * real linemode, attempt to negotiate kludge linemode by sending 99538904Sborman * the do timing mark sequence. 99638904Sborman */ 99738904Sborman if (lmodetype < REAL_LINEMODE) 99839503Sborman send_do(TELOPT_TM, 1); 99946809Sdab #endif /* defined(LINEMODE) && defined(KLUDGELINEMODE) */ 100038904Sborman 100138904Sborman /* 100238904Sborman * Call telrcv() once to pick up anything received during 100338904Sborman * terminal type negotiation, 4.2/4.3 determination, and 100438904Sborman * linemode negotiation. 100538904Sborman */ 100638904Sborman telrcv(); 100738904Sborman 100838904Sborman (void) ioctl(f, FIONBIO, (char *)&on); 100938904Sborman (void) ioctl(p, FIONBIO, (char *)&on); 101040242Sborman #if defined(CRAY2) && defined(UNICOS5) 101138904Sborman init_termdriver(f, p, interrupt, sendbrk); 101238904Sborman #endif 101338904Sborman 101438904Sborman #if defined(SO_OOBINLINE) 101557212Sdab (void) setsockopt(net, SOL_SOCKET, SO_OOBINLINE, 101657212Sdab (char *)&on, sizeof on); 101738904Sborman #endif /* defined(SO_OOBINLINE) */ 101838904Sborman 101938904Sborman #ifdef SIGTSTP 102038904Sborman (void) signal(SIGTSTP, SIG_IGN); 102138904Sborman #endif 102238904Sborman #ifdef SIGTTOU 102338904Sborman /* 102438904Sborman * Ignoring SIGTTOU keeps the kernel from blocking us 102538904Sborman * in ttioct() in /sys/tty.c. 102638904Sborman */ 102738904Sborman (void) signal(SIGTTOU, SIG_IGN); 102838904Sborman #endif 102938904Sborman 103038904Sborman (void) signal(SIGCHLD, cleanup); 103138904Sborman 103240242Sborman #if defined(CRAY2) && defined(UNICOS5) 103338904Sborman /* 103438904Sborman * Cray-2 will send a signal when pty modes are changed by slave 103538904Sborman * side. Set up signal handler now. 103638904Sborman */ 103738904Sborman if ((int)signal(SIGUSR1, termstat) < 0) 103838904Sborman perror("signal"); 103938904Sborman else if (ioctl(p, TCSIGME, (char *)SIGUSR1) < 0) 104038904Sborman perror("ioctl:TCSIGME"); 104138904Sborman /* 104238904Sborman * Make processing loop check terminal characteristics early on. 104338904Sborman */ 104438904Sborman termstat(); 104538904Sborman #endif 104638904Sborman 104745234Sborman #ifdef TIOCNOTTY 104845234Sborman { 104945234Sborman register int t; 105045234Sborman t = open(_PATH_TTY, O_RDWR); 105145234Sborman if (t >= 0) { 105245234Sborman (void) ioctl(t, TIOCNOTTY, (char *)0); 105345234Sborman (void) close(t); 105445234Sborman } 105545234Sborman } 105640242Sborman #endif 105745234Sborman 105846809Sdab #if defined(CRAY) && defined(NEWINIT) && defined(TIOCSCTTY) 105945234Sborman (void) setsid(); 106044363Sborman ioctl(p, TIOCSCTTY, 0); 106144363Sborman #endif 106238904Sborman 106338904Sborman /* 106412713Ssam * Show banner that getty never gave. 106527797Sminshall * 106633271Sminshall * We put the banner in the pty input buffer. This way, it 106733271Sminshall * gets carriage return null processing, etc., just like all 106833271Sminshall * other pty --> client data. 106912713Ssam */ 107027797Sminshall 107145234Sborman #if !defined(CRAY) || !defined(NEWINIT) 107245234Sborman if (getenv("USER")) 107345234Sborman hostinfo = 0; 107445234Sborman #endif 107538904Sborman 107633271Sminshall if (getent(defent, "default") == 1) { 107733271Sminshall char *getstr(); 107838904Sborman char *cp=defstrs; 107927649Sminshall 108038904Sborman HE = getstr("he", &cp); 108138904Sborman HN = getstr("hn", &cp); 108238904Sborman IM = getstr("im", &cp); 108333271Sminshall if (HN && *HN) 108446809Sdab (void) strcpy(host_name, HN); 108538904Sborman if (IM == 0) 108638904Sborman IM = ""; 108733271Sminshall } else { 108845234Sborman IM = DEFAULT_IM; 108938904Sborman HE = 0; 109033271Sminshall } 109146809Sdab edithost(HE, host_name); 109245234Sborman if (hostinfo && *IM) 109338904Sborman putf(IM, ptyibuf2); 109427797Sminshall 109538904Sborman if (pcc) 109638904Sborman (void) strncat(ptyibuf2, ptyip, pcc+1); 109738904Sborman ptyip = ptyibuf2; 109838904Sborman pcc = strlen(ptyip); 109940242Sborman #ifdef LINEMODE 110040242Sborman /* 110140242Sborman * Last check to make sure all our states are correct. 110240242Sborman */ 110340242Sborman init_termbuf(); 110440242Sborman localstat(); 110540242Sborman #endif /* LINEMODE */ 110633271Sminshall 110746809Sdab DIAG(TD_REPORT, 110846809Sdab {sprintf(nfrontp, "td: Entering processing loop\r\n"); 110946809Sdab nfrontp += strlen(nfrontp);}); 111044363Sborman 111145234Sborman #ifdef convex 111245234Sborman startslave(host); 111345234Sborman #endif 111445234Sborman 11156002Sroot for (;;) { 111627185Sminshall fd_set ibits, obits, xbits; 11176002Sroot register int c; 11186002Sroot 111927185Sminshall if (ncc < 0 && pcc < 0) 112027185Sminshall break; 112127185Sminshall 112240242Sborman #if defined(CRAY2) && defined(UNICOS5) 112338904Sborman if (needtermstat) 112438904Sborman _termstat(); 112540242Sborman #endif /* defined(CRAY2) && defined(UNICOS5) */ 112627185Sminshall FD_ZERO(&ibits); 112727185Sminshall FD_ZERO(&obits); 112827185Sminshall FD_ZERO(&xbits); 11296002Sroot /* 11306002Sroot * Never look for input if there's still 11316002Sroot * stuff in the corresponding output buffer 11326002Sroot */ 113327185Sminshall if (nfrontp - nbackp || pcc > 0) { 113427185Sminshall FD_SET(f, &obits); 113527185Sminshall } else { 113627185Sminshall FD_SET(p, &ibits); 113727185Sminshall } 113827185Sminshall if (pfrontp - pbackp || ncc > 0) { 113927185Sminshall FD_SET(p, &obits); 114027185Sminshall } else { 114127185Sminshall FD_SET(f, &ibits); 114227185Sminshall } 114327185Sminshall if (!SYNCHing) { 114427185Sminshall FD_SET(f, &xbits); 114527185Sminshall } 114627185Sminshall if ((c = select(16, &ibits, &obits, &xbits, 114727185Sminshall (struct timeval *)0)) < 1) { 114827185Sminshall if (c == -1) { 114927185Sminshall if (errno == EINTR) { 115027185Sminshall continue; 115127185Sminshall } 115227185Sminshall } 11536002Sroot sleep(5); 11546002Sroot continue; 11556002Sroot } 11566002Sroot 11576002Sroot /* 115827185Sminshall * Any urgent data? 115927185Sminshall */ 116027185Sminshall if (FD_ISSET(net, &xbits)) { 116127185Sminshall SYNCHing = 1; 116227185Sminshall } 116327185Sminshall 116427185Sminshall /* 11656002Sroot * Something to read from the network... 11666002Sroot */ 116727185Sminshall if (FD_ISSET(net, &ibits)) { 116827649Sminshall #if !defined(SO_OOBINLINE) 116927185Sminshall /* 117027898Skarels * In 4.2 (and 4.3 beta) systems, the 117127185Sminshall * OOB indication and data handling in the kernel 117227185Sminshall * is such that if two separate TCP Urgent requests 117327185Sminshall * come in, one byte of TCP data will be overlaid. 117427185Sminshall * This is fatal for Telnet, but we try to live 117527185Sminshall * with it. 117627185Sminshall * 117727185Sminshall * In addition, in 4.2 (and...), a special protocol 117827185Sminshall * is needed to pick up the TCP Urgent data in 117927185Sminshall * the correct sequence. 118027185Sminshall * 118127185Sminshall * What we do is: if we think we are in urgent 118227185Sminshall * mode, we look to see if we are "at the mark". 118327185Sminshall * If we are, we do an OOB receive. If we run 118427185Sminshall * this twice, we will do the OOB receive twice, 118527185Sminshall * but the second will fail, since the second 118627185Sminshall * time we were "at the mark", but there wasn't 118727185Sminshall * any data there (the kernel doesn't reset 118827185Sminshall * "at the mark" until we do a normal read). 118927185Sminshall * Once we've read the OOB data, we go ahead 119027185Sminshall * and do normal reads. 119127185Sminshall * 119227185Sminshall * There is also another problem, which is that 119327185Sminshall * since the OOB byte we read doesn't put us 119427185Sminshall * out of OOB state, and since that byte is most 119527185Sminshall * likely the TELNET DM (data mark), we would 119627185Sminshall * stay in the TELNET SYNCH (SYNCHing) state. 119727185Sminshall * So, clocks to the rescue. If we've "just" 119827185Sminshall * received a DM, then we test for the 119927185Sminshall * presence of OOB data when the receive OOB 120027185Sminshall * fails (and AFTER we did the normal mode read 120127185Sminshall * to clear "at the mark"). 120227185Sminshall */ 120327185Sminshall if (SYNCHing) { 120427185Sminshall int atmark; 120527185Sminshall 120638904Sborman (void) ioctl(net, SIOCATMARK, (char *)&atmark); 120727185Sminshall if (atmark) { 120827185Sminshall ncc = recv(net, netibuf, sizeof (netibuf), MSG_OOB); 120927185Sminshall if ((ncc == -1) && (errno == EINVAL)) { 121027185Sminshall ncc = read(net, netibuf, sizeof (netibuf)); 121127983Sminshall if (sequenceIs(didnetreceive, gotDM)) { 121227185Sminshall SYNCHing = stilloob(net); 121327185Sminshall } 121427185Sminshall } 121527185Sminshall } else { 121627185Sminshall ncc = read(net, netibuf, sizeof (netibuf)); 12176002Sroot } 121827185Sminshall } else { 121927185Sminshall ncc = read(net, netibuf, sizeof (netibuf)); 122027185Sminshall } 122127185Sminshall settimer(didnetreceive); 122227649Sminshall #else /* !defined(SO_OOBINLINE)) */ 122327185Sminshall ncc = read(net, netibuf, sizeof (netibuf)); 122427649Sminshall #endif /* !defined(SO_OOBINLINE)) */ 122527185Sminshall if (ncc < 0 && errno == EWOULDBLOCK) 122627185Sminshall ncc = 0; 122727185Sminshall else { 122827185Sminshall if (ncc <= 0) { 122927185Sminshall break; 123027185Sminshall } 123127185Sminshall netip = netibuf; 123227185Sminshall } 123346809Sdab DIAG((TD_REPORT | TD_NETDATA), 123446809Sdab {sprintf(nfrontp, "td: netread %d chars\r\n", ncc); 123546809Sdab nfrontp += strlen(nfrontp);}); 123646809Sdab DIAG(TD_NETDATA, printdata("nd", netip, ncc)); 12376002Sroot } 12386002Sroot 12396002Sroot /* 12406002Sroot * Something to read from the pty... 12416002Sroot */ 124238904Sborman if (FD_ISSET(p, &ibits)) { 124357212Sdab #ifndef STREAMSPTY 12446002Sroot pcc = read(p, ptyibuf, BUFSIZ); 124557212Sdab #else 124657212Sdab pcc = readstream(p, ptyibuf, BUFSIZ); 124757212Sdab #endif 124846809Sdab /* 124946809Sdab * On some systems, if we try to read something 125046809Sdab * off the master side before the slave side is 125146809Sdab * opened, we get EIO. 125246809Sdab */ 125357212Sdab if (pcc < 0 && (errno == EWOULDBLOCK || 125457212Sdab #ifdef EAGAIN 125557212Sdab errno == EAGAIN || 125657212Sdab #endif 125757212Sdab errno == EIO)) { 12586002Sroot pcc = 0; 125946809Sdab } else { 12606002Sroot if (pcc <= 0) 12616002Sroot break; 126240242Sborman #if !defined(CRAY2) || !defined(UNICOS5) 126338904Sborman #ifdef LINEMODE 126438904Sborman /* 126538904Sborman * If ioctl from pty, pass it through net 126638904Sborman */ 126738904Sborman if (ptyibuf[0] & TIOCPKT_IOCTL) { 126838904Sborman copy_termbuf(ptyibuf+1, pcc-1); 126938904Sborman localstat(); 127038904Sborman pcc = 1; 127138904Sborman } 127246809Sdab #endif /* LINEMODE */ 127337210Sminshall if (ptyibuf[0] & TIOCPKT_FLUSHWRITE) { 127438904Sborman netclear(); /* clear buffer back */ 127545234Sborman #ifndef NO_URGENT 127640242Sborman /* 127745234Sborman * There are client telnets on some 127840242Sborman * operating systems get screwed up 127940242Sborman * royally if we send them urgent 128045234Sborman * mode data. 128140242Sborman */ 128237210Sminshall *nfrontp++ = IAC; 128337210Sminshall *nfrontp++ = DM; 128437210Sminshall neturg = nfrontp-1; /* off by one XXX */ 128540242Sborman #endif 128637210Sminshall } 128744363Sborman if (his_state_is_will(TELOPT_LFLOW) && 128837210Sminshall (ptyibuf[0] & 128938904Sborman (TIOCPKT_NOSTOP|TIOCPKT_DOSTOP))) { 129057597Sdab int newflow = 129157597Sdab ptyibuf[0] & TIOCPKT_DOSTOP ? 1 : 0; 129257597Sdab if (newflow != flowmode) { 129357597Sdab flowmode = newflow; 129457597Sdab (void) sprintf(nfrontp, 129557597Sdab "%c%c%c%c%c%c", 129657597Sdab IAC, SB, TELOPT_LFLOW, 129757597Sdab flowmode ? LFLOW_ON 129857597Sdab : LFLOW_OFF, 129957597Sdab IAC, SE); 130057597Sdab nfrontp += 6; 130157597Sdab } 130237210Sminshall } 130333267Sminshall pcc--; 130433267Sminshall ptyip = ptyibuf+1; 130540242Sborman #else /* defined(CRAY2) && defined(UNICOS5) */ 130638904Sborman if (!uselinemode) { 130739531Sborman unpcc = pcc; 130839531Sborman unptyip = ptyibuf; 130939531Sborman pcc = term_output(&unptyip, ptyibuf2, 131039531Sborman &unpcc, BUFSIZ); 131138904Sborman ptyip = ptyibuf2; 131238904Sborman } else 131338904Sborman ptyip = ptyibuf; 131440242Sborman #endif /* defined(CRAY2) && defined(UNICOS5) */ 131538904Sborman } 13166002Sroot } 13176002Sroot 13186002Sroot while (pcc > 0) { 13196002Sroot if ((&netobuf[BUFSIZ] - nfrontp) < 2) 13206002Sroot break; 13216002Sroot c = *ptyip++ & 0377, pcc--; 13226002Sroot if (c == IAC) 13236002Sroot *nfrontp++ = c; 132440242Sborman #if defined(CRAY2) && defined(UNICOS5) 132538904Sborman else if (c == '\n' && 132644363Sborman my_state_is_wont(TELOPT_BINARY) && newmap) 132738904Sborman *nfrontp++ = '\r'; 132840242Sborman #endif /* defined(CRAY2) && defined(UNICOS5) */ 13296002Sroot *nfrontp++ = c; 133044363Sborman if ((c == '\r') && (my_state_is_wont(TELOPT_BINARY))) { 133127020Sminshall if (pcc > 0 && ((*ptyip & 0377) == '\n')) { 133227020Sminshall *nfrontp++ = *ptyip++ & 0377; 133327020Sminshall pcc--; 133427020Sminshall } else 133527020Sminshall *nfrontp++ = '\0'; 133627020Sminshall } 13376002Sroot } 133840242Sborman #if defined(CRAY2) && defined(UNICOS5) 133939531Sborman /* 134039531Sborman * If chars were left over from the terminal driver, 134139531Sborman * note their existence. 134239531Sborman */ 134346809Sdab if (!uselinemode && unpcc) { 134439531Sborman pcc = unpcc; 134539531Sborman unpcc = 0; 134639531Sborman ptyip = unptyip; 134739531Sborman } 134840242Sborman #endif /* defined(CRAY2) && defined(UNICOS5) */ 134939531Sborman 135027185Sminshall if (FD_ISSET(f, &obits) && (nfrontp - nbackp) > 0) 13516002Sroot netflush(); 13526002Sroot if (ncc > 0) 13536002Sroot telrcv(); 135427185Sminshall if (FD_ISSET(p, &obits) && (pfrontp - pbackp) > 0) 13556002Sroot ptyflush(); 13566002Sroot } 135746809Sdab cleanup(0); 135838904Sborman } /* end of telnet */ 13596002Sroot 136038904Sborman #ifndef TCSIG 136138904Sborman # ifdef TIOCSIG 136238904Sborman # define TCSIG TIOCSIG 136338904Sborman # endif 136438904Sborman #endif 13656002Sroot 136657212Sdab #ifdef STREAMSPTY 136757212Sdab 136857212Sdab int flowison = -1; /* current state of flow: -1 is unknown */ 136957212Sdab 137057212Sdab int readstream(p, ibuf, bufsize) 137157212Sdab int p; 137257212Sdab char *ibuf; 137357212Sdab int bufsize; 137457212Sdab { 137557212Sdab int flags = 0; 137657212Sdab int ret = 0; 137757212Sdab struct termios *tsp; 137857212Sdab struct termio *tp; 137957212Sdab struct iocblk *ip; 138057212Sdab char vstop, vstart; 138157212Sdab int ixon; 138257212Sdab int newflow; 138357212Sdab 138457212Sdab strbufc.maxlen = BUFSIZ; 138557212Sdab strbufc.buf = ctlbuf; 138657212Sdab strbufd.maxlen = bufsize-1; 138757212Sdab strbufd.len = 0; 138857212Sdab strbufd.buf = ibuf+1; 138957212Sdab ibuf[0] = 0; 139057212Sdab 139157212Sdab ret = getmsg(p, &strbufc, &strbufd, &flags); 139257212Sdab if (ret < 0) /* error of some sort -- probably EAGAIN */ 139357212Sdab return(-1); 139457212Sdab 139557212Sdab if (strbufc.len <= 0 || ctlbuf[0] == M_DATA) { 139657212Sdab /* data message */ 139757212Sdab if (strbufd.len > 0) { /* real data */ 139857212Sdab return(strbufd.len + 1); /* count header char */ 139957212Sdab } else { 140057212Sdab /* nothing there */ 140157212Sdab errno = EAGAIN; 140257212Sdab return(-1); 140357212Sdab } 140457212Sdab } 140557212Sdab 140657212Sdab /* 140757212Sdab * It's a control message. Return 1, to look at the flag we set 140857212Sdab */ 140957212Sdab 141057212Sdab switch (ctlbuf[0]) { 141157212Sdab case M_FLUSH: 141257212Sdab if (ibuf[1] & FLUSHW) 141357212Sdab ibuf[0] = TIOCPKT_FLUSHWRITE; 141457212Sdab return(1); 141557212Sdab 141657212Sdab case M_IOCTL: 141757212Sdab ip = (struct iocblk *) (ibuf+1); 141857212Sdab 141957212Sdab switch (ip->ioc_cmd) { 142057212Sdab case TCSETS: 142157212Sdab case TCSETSW: 142257212Sdab case TCSETSF: 142357212Sdab tsp = (struct termios *) 142457212Sdab (ibuf+1 + sizeof(struct iocblk)); 142557212Sdab vstop = tsp->c_cc[VSTOP]; 142657212Sdab vstart = tsp->c_cc[VSTART]; 142757212Sdab ixon = tsp->c_iflag & IXON; 142857212Sdab break; 142957212Sdab case TCSETA: 143057212Sdab case TCSETAW: 143157212Sdab case TCSETAF: 143257212Sdab tp = (struct termio *) (ibuf+1 + sizeof(struct iocblk)); 143357212Sdab vstop = tp->c_cc[VSTOP]; 143457212Sdab vstart = tp->c_cc[VSTART]; 143557212Sdab ixon = tp->c_iflag & IXON; 143657212Sdab break; 143757212Sdab default: 143857212Sdab errno = EAGAIN; 143957212Sdab return(-1); 144057212Sdab } 144157212Sdab 144257212Sdab newflow = (ixon && (vstart == 021) && (vstop == 023)) ? 1 : 0; 144357212Sdab if (newflow != flowison) { /* it's a change */ 144457212Sdab flowison = newflow; 144557212Sdab ibuf[0] = newflow ? TIOCPKT_DOSTOP : TIOCPKT_NOSTOP; 144657212Sdab return(1); 144757212Sdab } 144857212Sdab } 144957212Sdab 145057212Sdab /* nothing worth doing anything about */ 145157212Sdab errno = EAGAIN; 145257212Sdab return(-1); 145357212Sdab } 145457212Sdab #endif /* STREAMSPTY */ 145557212Sdab 145637212Sminshall /* 14576002Sroot * Send interrupt to process on other side of pty. 14586002Sroot * If it is in raw mode, just write NULL; 14596002Sroot * otherwise, write intr char. 14606002Sroot */ 146146809Sdab void 14626002Sroot interrupt() 14636002Sroot { 146438904Sborman ptyflush(); /* half-hearted */ 14656002Sroot 146638904Sborman #ifdef TCSIG 146738904Sborman (void) ioctl(pty, TCSIG, (char *)SIGINT); 146838904Sborman #else /* TCSIG */ 146938904Sborman init_termbuf(); 147040242Sborman *pfrontp++ = slctab[SLC_IP].sptr ? 147140242Sborman (unsigned char)*slctab[SLC_IP].sptr : '\177'; 147238904Sborman #endif /* TCSIG */ 14736002Sroot } 14746002Sroot 147527229Sminshall /* 147627229Sminshall * Send quit to process on other side of pty. 147727229Sminshall * If it is in raw mode, just write NULL; 147827229Sminshall * otherwise, write quit char. 147927229Sminshall */ 148046809Sdab void 148127229Sminshall sendbrk() 148227229Sminshall { 148327229Sminshall ptyflush(); /* half-hearted */ 148438904Sborman #ifdef TCSIG 148538904Sborman (void) ioctl(pty, TCSIG, (char *)SIGQUIT); 148638904Sborman #else /* TCSIG */ 148738904Sborman init_termbuf(); 148840242Sborman *pfrontp++ = slctab[SLC_ABORT].sptr ? 148940242Sborman (unsigned char)*slctab[SLC_ABORT].sptr : '\034'; 149038904Sborman #endif /* TCSIG */ 149127229Sminshall } 149227229Sminshall 149346809Sdab void 149438904Sborman sendsusp() 14956002Sroot { 149638904Sborman #ifdef SIGTSTP 149738904Sborman ptyflush(); /* half-hearted */ 149838904Sborman # ifdef TCSIG 149938904Sborman (void) ioctl(pty, TCSIG, (char *)SIGTSTP); 150038904Sborman # else /* TCSIG */ 150140242Sborman *pfrontp++ = slctab[SLC_SUSP].sptr ? 150240242Sborman (unsigned char)*slctab[SLC_SUSP].sptr : '\032'; 150338904Sborman # endif /* TCSIG */ 150438904Sborman #endif /* SIGTSTP */ 15056002Sroot } 15066002Sroot 150745234Sborman /* 150845234Sborman * When we get an AYT, if ^T is enabled, use that. Otherwise, 150945234Sborman * just send back "[Yes]". 151045234Sborman */ 151146809Sdab void 151245234Sborman recv_ayt() 151345234Sborman { 151445234Sborman #if defined(SIGINFO) && defined(TCSIG) 151545234Sborman if (slctab[SLC_AYT].sptr && *slctab[SLC_AYT].sptr != _POSIX_VDISABLE) { 151645234Sborman (void) ioctl(pty, TCSIG, (char *)SIGINFO); 151745234Sborman return; 151845234Sborman } 151945234Sborman #endif 152045234Sborman (void) strcpy(nfrontp, "\r\n[Yes]\r\n"); 152145234Sborman nfrontp += 9; 152245234Sborman } 152345234Sborman 152446809Sdab void 152538904Sborman doeof() 15266002Sroot { 152738904Sborman init_termbuf(); 15286002Sroot 152945234Sborman #if defined(LINEMODE) && defined(USE_TERMIO) && (VEOF == VMIN) 153040242Sborman if (!tty_isediting()) { 153146809Sdab extern char oldeofc; 153240242Sborman *pfrontp++ = oldeofc; 153340242Sborman return; 153440242Sborman } 153540242Sborman #endif 153640242Sborman *pfrontp++ = slctab[SLC_EOF].sptr ? 153740242Sborman (unsigned char)*slctab[SLC_EOF].sptr : '\004'; 15386002Sroot } 1539