121182Sdist /* 261451Sbostic * Copyright (c) 1989, 1993 361451Sbostic * The Regents of the University of California. All rights reserved. 433687Sbostic * 542673Sbostic * %sccs.include.redist.c% 621182Sdist */ 721182Sdist 86295Sroot #ifndef lint 961451Sbostic static char copyright[] = 1061451Sbostic "@(#) Copyright (c) 1989, 1993\n\ 1161451Sbostic The Regents of the University of California. All rights reserved.\n"; 1233687Sbostic #endif /* not lint */ 136295Sroot 1421182Sdist #ifndef lint 15*68346Sdab static char sccsid[] = "@(#)telnetd.c 8.3 (Berkeley) 02/16/95"; 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 */ 7165158Sdab long ptyibufbuf[BUFSIZ/sizeof(long)+1]; 7265158Sdab char *ptyibuf = ((char *)&ptyibufbuf[1])-1; 7365158Sdab char *ptyip = ((char *)&ptyibufbuf[1])-1; 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 */ 55865158Sdab static unsigned char ttytype_sbbuf[] = { 55965158Sdab IAC, SB, TELOPT_TTYPE, TELQUAL_SEND, IAC, SE 56065158Sdab }; 56146809Sdab 56246809Sdab int 56346809Sdab getterminaltype(name) 56446809Sdab char *name; 56527649Sminshall { 56646809Sdab int retval = -1; 56746809Sdab void _gettermname(); 56827649Sminshall 56938904Sborman settimer(baseline); 57057212Sdab #if defined(AUTHENTICATION) 57146809Sdab /* 57246809Sdab * Handle the Authentication option before we do anything else. 57346809Sdab */ 57446809Sdab send_do(TELOPT_AUTHENTICATION, 1); 57546809Sdab while (his_will_wont_is_changing(TELOPT_AUTHENTICATION)) 57646809Sdab ttloop(); 57746809Sdab if (his_state_is_will(TELOPT_AUTHENTICATION)) { 57846809Sdab retval = auth_wait(name); 57946809Sdab } 58046809Sdab #endif 58146809Sdab 58260151Sdab #ifdef ENCRYPTION 58346809Sdab send_will(TELOPT_ENCRYPT, 1); 58460151Sdab #endif /* ENCRYPTION */ 58539503Sborman send_do(TELOPT_TTYPE, 1); 58639503Sborman send_do(TELOPT_TSPEED, 1); 58744363Sborman send_do(TELOPT_XDISPLOC, 1); 58865158Sdab send_do(TELOPT_NEW_ENVIRON, 1); 58965158Sdab send_do(TELOPT_OLD_ENVIRON, 1); 59046809Sdab while ( 59160151Sdab #ifdef ENCRYPTION 59246809Sdab his_do_dont_is_changing(TELOPT_ENCRYPT) || 59360151Sdab #endif /* ENCRYPTION */ 59446809Sdab his_will_wont_is_changing(TELOPT_TTYPE) || 59544363Sborman his_will_wont_is_changing(TELOPT_TSPEED) || 59644363Sborman his_will_wont_is_changing(TELOPT_XDISPLOC) || 59765158Sdab his_will_wont_is_changing(TELOPT_NEW_ENVIRON) || 59865158Sdab his_will_wont_is_changing(TELOPT_OLD_ENVIRON)) { 59927983Sminshall ttloop(); 60027649Sminshall } 60160151Sdab #ifdef ENCRYPTION 60246809Sdab /* 60346809Sdab * Wait for the negotiation of what type of encryption we can 60446809Sdab * send with. If autoencrypt is not set, this will just return. 60546809Sdab */ 60646809Sdab if (his_state_is_will(TELOPT_ENCRYPT)) { 60746809Sdab encrypt_wait(); 60846809Sdab } 60960151Sdab #endif /* ENCRYPTION */ 61044363Sborman if (his_state_is_will(TELOPT_TSPEED)) { 61165158Sdab static unsigned char sb[] = 61265158Sdab { IAC, SB, TELOPT_TSPEED, TELQUAL_SEND, IAC, SE }; 61327983Sminshall 61465158Sdab bcopy(sb, nfrontp, sizeof sb); 61565158Sdab nfrontp += sizeof sb; 61638904Sborman } 61744363Sborman if (his_state_is_will(TELOPT_XDISPLOC)) { 61865158Sdab static unsigned char sb[] = 61965158Sdab { IAC, SB, TELOPT_XDISPLOC, TELQUAL_SEND, IAC, SE }; 62038904Sborman 62165158Sdab bcopy(sb, nfrontp, sizeof sb); 62265158Sdab nfrontp += sizeof sb; 62344363Sborman } 62465158Sdab if (his_state_is_will(TELOPT_NEW_ENVIRON)) { 62565158Sdab static unsigned char sb[] = 62665158Sdab { IAC, SB, TELOPT_NEW_ENVIRON, TELQUAL_SEND, IAC, SE }; 62744363Sborman 62865158Sdab bcopy(sb, nfrontp, sizeof sb); 62965158Sdab nfrontp += sizeof sb; 63044363Sborman } 63165158Sdab else if (his_state_is_will(TELOPT_OLD_ENVIRON)) { 63265158Sdab static unsigned char sb[] = 63365158Sdab { IAC, SB, TELOPT_OLD_ENVIRON, TELQUAL_SEND, IAC, SE }; 63465158Sdab 63565158Sdab bcopy(sb, nfrontp, sizeof sb); 63665158Sdab nfrontp += sizeof sb; 63765158Sdab } 63844363Sborman if (his_state_is_will(TELOPT_TTYPE)) { 63944363Sborman 64038904Sborman bcopy(ttytype_sbbuf, nfrontp, sizeof ttytype_sbbuf); 64138904Sborman nfrontp += sizeof ttytype_sbbuf; 64238904Sborman } 64344363Sborman if (his_state_is_will(TELOPT_TSPEED)) { 64438904Sborman while (sequenceIs(tspeedsubopt, baseline)) 64527983Sminshall ttloop(); 64638904Sborman } 64744363Sborman if (his_state_is_will(TELOPT_XDISPLOC)) { 64844363Sborman while (sequenceIs(xdisplocsubopt, baseline)) 64944363Sborman ttloop(); 65044363Sborman } 65165158Sdab if (his_state_is_will(TELOPT_NEW_ENVIRON)) { 65244363Sborman while (sequenceIs(environsubopt, baseline)) 65344363Sborman ttloop(); 65444363Sborman } 65565158Sdab if (his_state_is_will(TELOPT_OLD_ENVIRON)) { 65665158Sdab while (sequenceIs(oenvironsubopt, baseline)) 65765158Sdab ttloop(); 65865158Sdab } 65944363Sborman if (his_state_is_will(TELOPT_TTYPE)) { 66038904Sborman char first[256], last[256]; 66138904Sborman 66238904Sborman while (sequenceIs(ttypesubopt, baseline)) 66338904Sborman ttloop(); 66438904Sborman 66544363Sborman /* 66644363Sborman * If the other side has already disabled the option, then 66744363Sborman * we have to just go with what we (might) have already gotten. 66844363Sborman */ 66944363Sborman if (his_state_is_will(TELOPT_TTYPE) && !terminaltypeok(terminaltype)) { 67038904Sborman (void) strncpy(first, terminaltype, sizeof(first)); 67138904Sborman for(;;) { 67238904Sborman /* 67338904Sborman * Save the unknown name, and request the next name. 67438904Sborman */ 67538904Sborman (void) strncpy(last, terminaltype, sizeof(last)); 67638904Sborman _gettermname(); 67744363Sborman if (terminaltypeok(terminaltype)) 67838904Sborman break; 67944363Sborman if ((strncmp(last, terminaltype, sizeof(last)) == 0) || 68044363Sborman his_state_is_wont(TELOPT_TTYPE)) { 68138904Sborman /* 68238904Sborman * We've hit the end. If this is the same as 68338904Sborman * the first name, just go with it. 68438904Sborman */ 68545234Sborman if (strncmp(first, terminaltype, sizeof(first)) == 0) 68638904Sborman break; 68738904Sborman /* 68844363Sborman * Get the terminal name one more time, so that 68938904Sborman * RFC1091 compliant telnets will cycle back to 69038904Sborman * the start of the list. 69138904Sborman */ 69244363Sborman _gettermname(); 69345234Sborman if (strncmp(first, terminaltype, sizeof(first)) != 0) 69438904Sborman (void) strncpy(terminaltype, first, sizeof(first)); 69538904Sborman break; 69638904Sborman } 69738904Sborman } 69827983Sminshall } 69927983Sminshall } 70046809Sdab return(retval); 70138904Sborman } /* end of getterminaltype */ 70238904Sborman 70346809Sdab void 70438904Sborman _gettermname() 70538904Sborman { 70644363Sborman /* 70744363Sborman * If the client turned off the option, 70844363Sborman * we can't send another request, so we 70944363Sborman * just return. 71044363Sborman */ 71144363Sborman if (his_state_is_wont(TELOPT_TTYPE)) 71244363Sborman return; 71338904Sborman settimer(baseline); 71438904Sborman bcopy(ttytype_sbbuf, nfrontp, sizeof ttytype_sbbuf); 71538904Sborman nfrontp += sizeof ttytype_sbbuf; 71638904Sborman while (sequenceIs(ttypesubopt, baseline)) 71738904Sborman ttloop(); 71827649Sminshall } 71927649Sminshall 72046809Sdab int 72138904Sborman terminaltypeok(s) 72246809Sdab char *s; 72338904Sborman { 72438904Sborman char buf[1024]; 72538904Sborman 72638904Sborman if (terminaltype == NULL) 72738904Sborman return(1); 72838904Sborman 72938904Sborman /* 73038904Sborman * tgetent() will return 1 if the type is known, and 73138904Sborman * 0 if it is not known. If it returns -1, it couldn't 73238904Sborman * open the database. But if we can't open the database, 73338904Sborman * it won't help to say we failed, because we won't be 73438904Sborman * able to verify anything else. So, we treat -1 like 1. 73538904Sborman */ 73638904Sborman if (tgetent(buf, s) == 0) 73738904Sborman return(0); 73838904Sborman return(1); 73938904Sborman } 74038904Sborman 74146809Sdab #ifndef MAXHOSTNAMELEN 74246809Sdab #define MAXHOSTNAMELEN 64 74346809Sdab #endif /* MAXHOSTNAMELEN */ 74446809Sdab 74546809Sdab char *hostname; 74646809Sdab char host_name[MAXHOSTNAMELEN]; 74746809Sdab char remote_host_name[MAXHOSTNAMELEN]; 74846809Sdab 74946809Sdab #ifndef convex 75046809Sdab extern void telnet P((int, int)); 75146809Sdab #else 75246809Sdab extern void telnet P((int, int, char *)); 75346809Sdab #endif 75446809Sdab 7556002Sroot /* 7566002Sroot * Get a pty, scan input lines. 7576002Sroot */ 75838904Sborman doit(who) 75912683Ssam struct sockaddr_in *who; 7606002Sroot { 76120188Skarels char *host, *inet_ntoa(); 76238904Sborman int t; 76312683Ssam struct hostent *hp; 76446809Sdab int level; 76560151Sdab int ptynum; 76646809Sdab char user_name[256]; 7676002Sroot 76838904Sborman /* 76938904Sborman * Find an available pty to use. 77038904Sborman */ 77145234Sborman #ifndef convex 77260151Sdab pty = getpty(&ptynum); 77338904Sborman if (pty < 0) 77438904Sborman fatal(net, "All network ports in use"); 77545234Sborman #else 77645234Sborman for (;;) { 77745234Sborman char *lp; 77845234Sborman extern char *line, *getpty(); 77920188Skarels 78045234Sborman if ((lp = getpty()) == NULL) 78145234Sborman fatal(net, "Out of ptys"); 78245234Sborman 78345234Sborman if ((pty = open(lp, 2)) >= 0) { 78445234Sborman strcpy(line,lp); 78545234Sborman line[5] = 't'; 78645234Sborman break; 78745234Sborman } 78845234Sborman } 78944545Smarc #endif 79038904Sborman 79157212Sdab #if defined(_SC_CRAY_SECURE_SYS) 79257212Sdab /* 79357212Sdab * set ttyp line security label 79457212Sdab */ 79557212Sdab if (secflag) { 79660151Sdab char slave_dev[16]; 79760151Sdab 79860151Sdab sprintf(tty_dev, "/dev/pty/%03d", ptynum); 79960151Sdab if (setdevs(tty_dev, &dv) < 0) 80060151Sdab fatal(net, "cannot set pty security"); 80160151Sdab sprintf(slave_dev, "/dev/ttyp%03d", ptynum); 80260151Sdab if (setdevs(slave_dev, &dv) < 0) 80360151Sdab fatal(net, "cannot set tty security"); 80457212Sdab } 80557212Sdab #endif /* _SC_CRAY_SECURE_SYS */ 80657212Sdab 80738904Sborman /* get name of connected client */ 80838904Sborman hp = gethostbyaddr((char *)&who->sin_addr, sizeof (struct in_addr), 80912683Ssam who->sin_family); 81057212Sdab 81157641Sdab if (hp == NULL && registerd_host_only) { 81257641Sdab fatal(net, "Couldn't resolve your address into a host name.\r\n\ 81357641Sdab Please contact your net administrator"); 81457641Sdab } else if (hp && 81557212Sdab (strlen(hp->h_name) <= ((utmp_len < 0) ? -utmp_len : utmp_len))) { 81612683Ssam host = hp->h_name; 81757212Sdab } else { 81817444Sralph host = inet_ntoa(who->sin_addr); 81957212Sdab } 82046809Sdab /* 82146809Sdab * We must make a copy because Kerberos is probably going 82246809Sdab * to also do a gethost* and overwrite the static data... 82346809Sdab */ 82446809Sdab strncpy(remote_host_name, host, sizeof(remote_host_name)-1); 82546809Sdab remote_host_name[sizeof(remote_host_name)-1] = 0; 82646809Sdab host = remote_host_name; 82727983Sminshall 82846809Sdab (void) gethostname(host_name, sizeof (host_name)); 82946809Sdab hostname = host_name; 83046809Sdab 83157212Sdab #if defined(AUTHENTICATION) || defined(ENCRYPTION) 83246809Sdab auth_encrypt_init(hostname, host, "TELNETD", 1); 83346809Sdab #endif 83446809Sdab 83544363Sborman init_env(); 83627983Sminshall /* 83738904Sborman * get terminal type. 83827983Sminshall */ 83946809Sdab *user_name = 0; 84046809Sdab level = getterminaltype(user_name); 84144363Sborman setenv("TERM", terminaltype ? terminaltype : "network", 1); 84227983Sminshall 84327649Sminshall /* 84438904Sborman * Start up the login process on the slave side of the terminal 84527649Sminshall */ 84645234Sborman #ifndef convex 84746809Sdab startslave(host, level, user_name); 84838904Sborman 84960151Sdab #if defined(_SC_CRAY_SECURE_SYS) 85060151Sdab if (secflag) { 85160151Sdab if (setulvl(dv.dv_actlvl) < 0) 85260151Sdab fatal(net,"cannot setulvl()"); 85360151Sdab if (setucmp(dv.dv_actcmp) < 0) 85460151Sdab fatal(net, "cannot setucmp()"); 85560151Sdab } 85660151Sdab #endif /* _SC_CRAY_SECURE_SYS */ 85760151Sdab 85838904Sborman telnet(net, pty); /* begin server processing */ 85945234Sborman #else 86045234Sborman telnet(net, pty, host); 86145234Sborman #endif 8629244Ssam /*NOTREACHED*/ 86338904Sborman } /* end of doit */ 8649244Ssam 86546809Sdab #if defined(CRAY2) && defined(UNICOS5) && defined(UNICOS50) 86646809Sdab int 86746809Sdab Xterm_output(ibufp, obuf, icountp, ocount) 86846809Sdab char **ibufp, *obuf; 86946809Sdab int *icountp, ocount; 87046809Sdab { 87146809Sdab int ret; 87246809Sdab ret = term_output(*ibufp, obuf, *icountp, ocount); 87346809Sdab *ibufp += *icountp; 87446809Sdab *icountp = 0; 87546809Sdab return(ret); 87646809Sdab } 87746809Sdab #define term_output Xterm_output 87846809Sdab #endif /* defined(CRAY2) && defined(UNICOS5) && defined(UNICOS50) */ 87946809Sdab 8806002Sroot /* 8816002Sroot * Main loop. Select from pty and network, and 8826002Sroot * hand data to telnet receiver finite state machine. 8836002Sroot */ 88446809Sdab void 88545234Sborman #ifndef convex 8866002Sroot telnet(f, p) 88745234Sborman #else 88845234Sborman telnet(f, p, host) 88945234Sborman #endif 89046809Sdab int f, p; 89145234Sborman #ifdef convex 89246809Sdab char *host; 89345234Sborman #endif 8946002Sroot { 8956002Sroot int on = 1; 89633271Sminshall #define TABBUFSIZ 512 89733271Sminshall char defent[TABBUFSIZ]; 89833271Sminshall char defstrs[TABBUFSIZ]; 89933271Sminshall #undef TABBUFSIZ 90033271Sminshall char *HE; 90133271Sminshall char *HN; 90233271Sminshall char *IM; 90338904Sborman void netflush(); 904*68346Sdab int nfd; 90546809Sdab 90632400Sminshall /* 90738904Sborman * Initialize the slc mapping table. 90832400Sminshall */ 90938904Sborman get_slc_defaults(); 9106002Sroot 9118379Ssam /* 91238904Sborman * Do some tests where it is desireable to wait for a response. 91338904Sborman * Rather than doing them slowly, one at a time, do them all 91438904Sborman * at once. 9158379Ssam */ 91644363Sborman if (my_state_is_wont(TELOPT_SGA)) 91739503Sborman send_will(TELOPT_SGA, 1); 91812713Ssam /* 91927649Sminshall * Is the client side a 4.2 (NOT 4.3) system? We need to know this 92027649Sminshall * because 4.2 clients are unable to deal with TCP urgent data. 92127649Sminshall * 92227649Sminshall * To find out, we send out a "DO ECHO". If the remote system 92327649Sminshall * answers "WILL ECHO" it is probably a 4.2 client, and we note 92427649Sminshall * that fact ("WILL ECHO" ==> that the client will echo what 92527649Sminshall * WE, the server, sends it; it does NOT mean that the client will 92627649Sminshall * echo the terminal input). 92727649Sminshall */ 92839503Sborman send_do(TELOPT_ECHO, 1); 92927649Sminshall 93038904Sborman #ifdef LINEMODE 93144363Sborman if (his_state_is_wont(TELOPT_LINEMODE)) { 93238904Sborman /* Query the peer for linemode support by trying to negotiate 93338904Sborman * the linemode option. 93438904Sborman */ 93544363Sborman linemode = 0; 93638904Sborman editmode = 0; 93739503Sborman send_do(TELOPT_LINEMODE, 1); /* send do linemode */ 93838904Sborman } 93938904Sborman #endif /* LINEMODE */ 94038904Sborman 94127649Sminshall /* 94238904Sborman * Send along a couple of other options that we wish to negotiate. 94338904Sborman */ 94439503Sborman send_do(TELOPT_NAWS, 1); 94539503Sborman send_will(TELOPT_STATUS, 1); 94657597Sdab flowmode = 1; /* default flow control state */ 94757597Sdab restartany = -1; /* uninitialized... */ 94839503Sborman send_do(TELOPT_LFLOW, 1); 94938904Sborman 95038904Sborman /* 95138904Sborman * Spin, waiting for a response from the DO ECHO. However, 95238904Sborman * some REALLY DUMB telnets out there might not respond 95338904Sborman * to the DO ECHO. So, we spin looking for NAWS, (most dumb 95438904Sborman * telnets so far seem to respond with WONT for a DO that 95538904Sborman * they don't understand...) because by the time we get the 95638904Sborman * response, it will already have processed the DO ECHO. 95738904Sborman * Kludge upon kludge. 95838904Sborman */ 95944363Sborman while (his_will_wont_is_changing(TELOPT_NAWS)) 96038904Sborman ttloop(); 96138904Sborman 96238904Sborman /* 96344363Sborman * But... 96444363Sborman * The client might have sent a WILL NAWS as part of its 96544363Sborman * startup code; if so, we'll be here before we get the 96644363Sborman * response to the DO ECHO. We'll make the assumption 96744363Sborman * that any implementation that understands about NAWS 96844363Sborman * is a modern enough implementation that it will respond 96944363Sborman * to our DO ECHO request; hence we'll do another spin 97044363Sborman * waiting for the ECHO option to settle down, which is 97144363Sborman * what we wanted to do in the first place... 97244363Sborman */ 97344363Sborman if (his_want_state_is_will(TELOPT_ECHO) && 97444363Sborman his_state_is_will(TELOPT_NAWS)) { 97544363Sborman while (his_will_wont_is_changing(TELOPT_ECHO)) 97644363Sborman ttloop(); 97744363Sborman } 97844363Sborman /* 97938995Sborman * On the off chance that the telnet client is broken and does not 98038995Sborman * respond to the DO ECHO we sent, (after all, we did send the 98138995Sborman * DO NAWS negotiation after the DO ECHO, and we won't get here 98238995Sborman * until a response to the DO NAWS comes back) simulate the 98338995Sborman * receipt of a will echo. This will also send a WONT ECHO 98438995Sborman * to the client, since we assume that the client failed to 98538995Sborman * respond because it believes that it is already in DO ECHO 98638995Sborman * mode, which we do not want. 98738995Sborman */ 98844363Sborman if (his_want_state_is_will(TELOPT_ECHO)) { 98946809Sdab DIAG(TD_OPTIONS, 99046809Sdab {sprintf(nfrontp, "td: simulating recv\r\n"); 99146809Sdab nfrontp += strlen(nfrontp);}); 99239503Sborman willoption(TELOPT_ECHO); 99340242Sborman } 99438995Sborman 99538995Sborman /* 99638995Sborman * Finally, to clean things up, we turn on our echo. This 99738995Sborman * will break stupid 4.2 telnets out of local terminal echo. 99838995Sborman */ 99938995Sborman 100044363Sborman if (my_state_is_wont(TELOPT_ECHO)) 100139503Sborman send_will(TELOPT_ECHO, 1); 100238995Sborman 100357212Sdab #ifndef STREAMSPTY 100438995Sborman /* 100545234Sborman * Turn on packet mode 100638904Sborman */ 100738904Sborman (void) ioctl(p, TIOCPKT, (char *)&on); 100857212Sdab #endif 100957212Sdab 101046809Sdab #if defined(LINEMODE) && defined(KLUDGELINEMODE) 101138904Sborman /* 101238904Sborman * Continuing line mode support. If client does not support 101338904Sborman * real linemode, attempt to negotiate kludge linemode by sending 101438904Sborman * the do timing mark sequence. 101538904Sborman */ 101638904Sborman if (lmodetype < REAL_LINEMODE) 101739503Sborman send_do(TELOPT_TM, 1); 101846809Sdab #endif /* defined(LINEMODE) && defined(KLUDGELINEMODE) */ 101938904Sborman 102038904Sborman /* 102138904Sborman * Call telrcv() once to pick up anything received during 102238904Sborman * terminal type negotiation, 4.2/4.3 determination, and 102338904Sborman * linemode negotiation. 102438904Sborman */ 102538904Sborman telrcv(); 102638904Sborman 102738904Sborman (void) ioctl(f, FIONBIO, (char *)&on); 102838904Sborman (void) ioctl(p, FIONBIO, (char *)&on); 102940242Sborman #if defined(CRAY2) && defined(UNICOS5) 103038904Sborman init_termdriver(f, p, interrupt, sendbrk); 103138904Sborman #endif 103238904Sborman 103338904Sborman #if defined(SO_OOBINLINE) 103457212Sdab (void) setsockopt(net, SOL_SOCKET, SO_OOBINLINE, 103557212Sdab (char *)&on, sizeof on); 103638904Sborman #endif /* defined(SO_OOBINLINE) */ 103738904Sborman 103838904Sborman #ifdef SIGTSTP 103938904Sborman (void) signal(SIGTSTP, SIG_IGN); 104038904Sborman #endif 104138904Sborman #ifdef SIGTTOU 104238904Sborman /* 104338904Sborman * Ignoring SIGTTOU keeps the kernel from blocking us 104438904Sborman * in ttioct() in /sys/tty.c. 104538904Sborman */ 104638904Sborman (void) signal(SIGTTOU, SIG_IGN); 104738904Sborman #endif 104838904Sborman 104938904Sborman (void) signal(SIGCHLD, cleanup); 105038904Sborman 105140242Sborman #if defined(CRAY2) && defined(UNICOS5) 105238904Sborman /* 105338904Sborman * Cray-2 will send a signal when pty modes are changed by slave 105438904Sborman * side. Set up signal handler now. 105538904Sborman */ 105638904Sborman if ((int)signal(SIGUSR1, termstat) < 0) 105738904Sborman perror("signal"); 105838904Sborman else if (ioctl(p, TCSIGME, (char *)SIGUSR1) < 0) 105938904Sborman perror("ioctl:TCSIGME"); 106038904Sborman /* 106138904Sborman * Make processing loop check terminal characteristics early on. 106238904Sborman */ 106338904Sborman termstat(); 106438904Sborman #endif 106538904Sborman 106645234Sborman #ifdef TIOCNOTTY 106745234Sborman { 106845234Sborman register int t; 106945234Sborman t = open(_PATH_TTY, O_RDWR); 107045234Sborman if (t >= 0) { 107145234Sborman (void) ioctl(t, TIOCNOTTY, (char *)0); 107245234Sborman (void) close(t); 107345234Sborman } 107445234Sborman } 107540242Sborman #endif 107645234Sborman 107746809Sdab #if defined(CRAY) && defined(NEWINIT) && defined(TIOCSCTTY) 107845234Sborman (void) setsid(); 107944363Sborman ioctl(p, TIOCSCTTY, 0); 108044363Sborman #endif 108138904Sborman 108238904Sborman /* 108312713Ssam * Show banner that getty never gave. 108427797Sminshall * 108533271Sminshall * We put the banner in the pty input buffer. This way, it 108633271Sminshall * gets carriage return null processing, etc., just like all 108733271Sminshall * other pty --> client data. 108812713Ssam */ 108927797Sminshall 109045234Sborman #if !defined(CRAY) || !defined(NEWINIT) 109145234Sborman if (getenv("USER")) 109245234Sborman hostinfo = 0; 109345234Sborman #endif 109438904Sborman 109533271Sminshall if (getent(defent, "default") == 1) { 109633271Sminshall char *getstr(); 109738904Sborman char *cp=defstrs; 109827649Sminshall 109938904Sborman HE = getstr("he", &cp); 110038904Sborman HN = getstr("hn", &cp); 110138904Sborman IM = getstr("im", &cp); 110233271Sminshall if (HN && *HN) 110346809Sdab (void) strcpy(host_name, HN); 110438904Sborman if (IM == 0) 110538904Sborman IM = ""; 110633271Sminshall } else { 110745234Sborman IM = DEFAULT_IM; 110838904Sborman HE = 0; 110933271Sminshall } 111046809Sdab edithost(HE, host_name); 111145234Sborman if (hostinfo && *IM) 111238904Sborman putf(IM, ptyibuf2); 111327797Sminshall 111438904Sborman if (pcc) 111538904Sborman (void) strncat(ptyibuf2, ptyip, pcc+1); 111638904Sborman ptyip = ptyibuf2; 111738904Sborman pcc = strlen(ptyip); 111840242Sborman #ifdef LINEMODE 111940242Sborman /* 112040242Sborman * Last check to make sure all our states are correct. 112140242Sborman */ 112240242Sborman init_termbuf(); 112340242Sborman localstat(); 112440242Sborman #endif /* LINEMODE */ 112533271Sminshall 112646809Sdab DIAG(TD_REPORT, 112746809Sdab {sprintf(nfrontp, "td: Entering processing loop\r\n"); 112846809Sdab nfrontp += strlen(nfrontp);}); 112944363Sborman 113045234Sborman #ifdef convex 113145234Sborman startslave(host); 113245234Sborman #endif 113345234Sborman 1134*68346Sdab nfd = ((f > p) ? f : p) + 1; 11356002Sroot for (;;) { 113627185Sminshall fd_set ibits, obits, xbits; 11376002Sroot register int c; 11386002Sroot 113927185Sminshall if (ncc < 0 && pcc < 0) 114027185Sminshall break; 114127185Sminshall 114240242Sborman #if defined(CRAY2) && defined(UNICOS5) 114338904Sborman if (needtermstat) 114438904Sborman _termstat(); 114540242Sborman #endif /* defined(CRAY2) && defined(UNICOS5) */ 114627185Sminshall FD_ZERO(&ibits); 114727185Sminshall FD_ZERO(&obits); 114827185Sminshall FD_ZERO(&xbits); 11496002Sroot /* 11506002Sroot * Never look for input if there's still 11516002Sroot * stuff in the corresponding output buffer 11526002Sroot */ 115327185Sminshall if (nfrontp - nbackp || pcc > 0) { 115427185Sminshall FD_SET(f, &obits); 115527185Sminshall } else { 115627185Sminshall FD_SET(p, &ibits); 115727185Sminshall } 115827185Sminshall if (pfrontp - pbackp || ncc > 0) { 115927185Sminshall FD_SET(p, &obits); 116027185Sminshall } else { 116127185Sminshall FD_SET(f, &ibits); 116227185Sminshall } 116327185Sminshall if (!SYNCHing) { 116427185Sminshall FD_SET(f, &xbits); 116527185Sminshall } 1166*68346Sdab if ((c = select(nfd, &ibits, &obits, &xbits, 116727185Sminshall (struct timeval *)0)) < 1) { 116827185Sminshall if (c == -1) { 116927185Sminshall if (errno == EINTR) { 117027185Sminshall continue; 117127185Sminshall } 117227185Sminshall } 11736002Sroot sleep(5); 11746002Sroot continue; 11756002Sroot } 11766002Sroot 11776002Sroot /* 117827185Sminshall * Any urgent data? 117927185Sminshall */ 118027185Sminshall if (FD_ISSET(net, &xbits)) { 118127185Sminshall SYNCHing = 1; 118227185Sminshall } 118327185Sminshall 118427185Sminshall /* 11856002Sroot * Something to read from the network... 11866002Sroot */ 118727185Sminshall if (FD_ISSET(net, &ibits)) { 118827649Sminshall #if !defined(SO_OOBINLINE) 118927185Sminshall /* 119027898Skarels * In 4.2 (and 4.3 beta) systems, the 119127185Sminshall * OOB indication and data handling in the kernel 119227185Sminshall * is such that if two separate TCP Urgent requests 119327185Sminshall * come in, one byte of TCP data will be overlaid. 119427185Sminshall * This is fatal for Telnet, but we try to live 119527185Sminshall * with it. 119627185Sminshall * 119727185Sminshall * In addition, in 4.2 (and...), a special protocol 119827185Sminshall * is needed to pick up the TCP Urgent data in 119927185Sminshall * the correct sequence. 120027185Sminshall * 120127185Sminshall * What we do is: if we think we are in urgent 120227185Sminshall * mode, we look to see if we are "at the mark". 120327185Sminshall * If we are, we do an OOB receive. If we run 120427185Sminshall * this twice, we will do the OOB receive twice, 120527185Sminshall * but the second will fail, since the second 120627185Sminshall * time we were "at the mark", but there wasn't 120727185Sminshall * any data there (the kernel doesn't reset 120827185Sminshall * "at the mark" until we do a normal read). 120927185Sminshall * Once we've read the OOB data, we go ahead 121027185Sminshall * and do normal reads. 121127185Sminshall * 121227185Sminshall * There is also another problem, which is that 121327185Sminshall * since the OOB byte we read doesn't put us 121427185Sminshall * out of OOB state, and since that byte is most 121527185Sminshall * likely the TELNET DM (data mark), we would 121627185Sminshall * stay in the TELNET SYNCH (SYNCHing) state. 121727185Sminshall * So, clocks to the rescue. If we've "just" 121827185Sminshall * received a DM, then we test for the 121927185Sminshall * presence of OOB data when the receive OOB 122027185Sminshall * fails (and AFTER we did the normal mode read 122127185Sminshall * to clear "at the mark"). 122227185Sminshall */ 122327185Sminshall if (SYNCHing) { 122427185Sminshall int atmark; 122527185Sminshall 122638904Sborman (void) ioctl(net, SIOCATMARK, (char *)&atmark); 122727185Sminshall if (atmark) { 122827185Sminshall ncc = recv(net, netibuf, sizeof (netibuf), MSG_OOB); 122927185Sminshall if ((ncc == -1) && (errno == EINVAL)) { 123027185Sminshall ncc = read(net, netibuf, sizeof (netibuf)); 123127983Sminshall if (sequenceIs(didnetreceive, gotDM)) { 123227185Sminshall SYNCHing = stilloob(net); 123327185Sminshall } 123427185Sminshall } 123527185Sminshall } else { 123627185Sminshall ncc = read(net, netibuf, sizeof (netibuf)); 12376002Sroot } 123827185Sminshall } else { 123927185Sminshall ncc = read(net, netibuf, sizeof (netibuf)); 124027185Sminshall } 124127185Sminshall settimer(didnetreceive); 124227649Sminshall #else /* !defined(SO_OOBINLINE)) */ 124327185Sminshall ncc = read(net, netibuf, sizeof (netibuf)); 124427649Sminshall #endif /* !defined(SO_OOBINLINE)) */ 124527185Sminshall if (ncc < 0 && errno == EWOULDBLOCK) 124627185Sminshall ncc = 0; 124727185Sminshall else { 124827185Sminshall if (ncc <= 0) { 124927185Sminshall break; 125027185Sminshall } 125127185Sminshall netip = netibuf; 125227185Sminshall } 125346809Sdab DIAG((TD_REPORT | TD_NETDATA), 125446809Sdab {sprintf(nfrontp, "td: netread %d chars\r\n", ncc); 125546809Sdab nfrontp += strlen(nfrontp);}); 125646809Sdab DIAG(TD_NETDATA, printdata("nd", netip, ncc)); 12576002Sroot } 12586002Sroot 12596002Sroot /* 12606002Sroot * Something to read from the pty... 12616002Sroot */ 126238904Sborman if (FD_ISSET(p, &ibits)) { 126357212Sdab #ifndef STREAMSPTY 12646002Sroot pcc = read(p, ptyibuf, BUFSIZ); 126557212Sdab #else 126657212Sdab pcc = readstream(p, ptyibuf, BUFSIZ); 126757212Sdab #endif 126846809Sdab /* 126946809Sdab * On some systems, if we try to read something 127046809Sdab * off the master side before the slave side is 127146809Sdab * opened, we get EIO. 127246809Sdab */ 127357212Sdab if (pcc < 0 && (errno == EWOULDBLOCK || 127457212Sdab #ifdef EAGAIN 127557212Sdab errno == EAGAIN || 127657212Sdab #endif 127757212Sdab errno == EIO)) { 12786002Sroot pcc = 0; 127946809Sdab } else { 12806002Sroot if (pcc <= 0) 12816002Sroot break; 128240242Sborman #if !defined(CRAY2) || !defined(UNICOS5) 128338904Sborman #ifdef LINEMODE 128438904Sborman /* 128538904Sborman * If ioctl from pty, pass it through net 128638904Sborman */ 128738904Sborman if (ptyibuf[0] & TIOCPKT_IOCTL) { 128838904Sborman copy_termbuf(ptyibuf+1, pcc-1); 128938904Sborman localstat(); 129038904Sborman pcc = 1; 129138904Sborman } 129246809Sdab #endif /* LINEMODE */ 129337210Sminshall if (ptyibuf[0] & TIOCPKT_FLUSHWRITE) { 129438904Sborman netclear(); /* clear buffer back */ 129545234Sborman #ifndef NO_URGENT 129640242Sborman /* 129745234Sborman * There are client telnets on some 129840242Sborman * operating systems get screwed up 129940242Sborman * royally if we send them urgent 130045234Sborman * mode data. 130140242Sborman */ 130237210Sminshall *nfrontp++ = IAC; 130337210Sminshall *nfrontp++ = DM; 130437210Sminshall neturg = nfrontp-1; /* off by one XXX */ 130540242Sborman #endif 130637210Sminshall } 130744363Sborman if (his_state_is_will(TELOPT_LFLOW) && 130837210Sminshall (ptyibuf[0] & 130938904Sborman (TIOCPKT_NOSTOP|TIOCPKT_DOSTOP))) { 131057597Sdab int newflow = 131157597Sdab ptyibuf[0] & TIOCPKT_DOSTOP ? 1 : 0; 131257597Sdab if (newflow != flowmode) { 131357597Sdab flowmode = newflow; 131457597Sdab (void) sprintf(nfrontp, 131557597Sdab "%c%c%c%c%c%c", 131657597Sdab IAC, SB, TELOPT_LFLOW, 131757597Sdab flowmode ? LFLOW_ON 131857597Sdab : LFLOW_OFF, 131957597Sdab IAC, SE); 132057597Sdab nfrontp += 6; 132157597Sdab } 132237210Sminshall } 132333267Sminshall pcc--; 132433267Sminshall ptyip = ptyibuf+1; 132540242Sborman #else /* defined(CRAY2) && defined(UNICOS5) */ 132638904Sborman if (!uselinemode) { 132739531Sborman unpcc = pcc; 132839531Sborman unptyip = ptyibuf; 132939531Sborman pcc = term_output(&unptyip, ptyibuf2, 133039531Sborman &unpcc, BUFSIZ); 133138904Sborman ptyip = ptyibuf2; 133238904Sborman } else 133338904Sborman ptyip = ptyibuf; 133440242Sborman #endif /* defined(CRAY2) && defined(UNICOS5) */ 133538904Sborman } 13366002Sroot } 13376002Sroot 13386002Sroot while (pcc > 0) { 13396002Sroot if ((&netobuf[BUFSIZ] - nfrontp) < 2) 13406002Sroot break; 13416002Sroot c = *ptyip++ & 0377, pcc--; 13426002Sroot if (c == IAC) 13436002Sroot *nfrontp++ = c; 134440242Sborman #if defined(CRAY2) && defined(UNICOS5) 134538904Sborman else if (c == '\n' && 134644363Sborman my_state_is_wont(TELOPT_BINARY) && newmap) 134738904Sborman *nfrontp++ = '\r'; 134840242Sborman #endif /* defined(CRAY2) && defined(UNICOS5) */ 13496002Sroot *nfrontp++ = c; 135044363Sborman if ((c == '\r') && (my_state_is_wont(TELOPT_BINARY))) { 135127020Sminshall if (pcc > 0 && ((*ptyip & 0377) == '\n')) { 135227020Sminshall *nfrontp++ = *ptyip++ & 0377; 135327020Sminshall pcc--; 135427020Sminshall } else 135527020Sminshall *nfrontp++ = '\0'; 135627020Sminshall } 13576002Sroot } 135840242Sborman #if defined(CRAY2) && defined(UNICOS5) 135939531Sborman /* 136039531Sborman * If chars were left over from the terminal driver, 136139531Sborman * note their existence. 136239531Sborman */ 136346809Sdab if (!uselinemode && unpcc) { 136439531Sborman pcc = unpcc; 136539531Sborman unpcc = 0; 136639531Sborman ptyip = unptyip; 136739531Sborman } 136840242Sborman #endif /* defined(CRAY2) && defined(UNICOS5) */ 136939531Sborman 137027185Sminshall if (FD_ISSET(f, &obits) && (nfrontp - nbackp) > 0) 13716002Sroot netflush(); 13726002Sroot if (ncc > 0) 13736002Sroot telrcv(); 137427185Sminshall if (FD_ISSET(p, &obits) && (pfrontp - pbackp) > 0) 13756002Sroot ptyflush(); 13766002Sroot } 137746809Sdab cleanup(0); 137838904Sborman } /* end of telnet */ 13796002Sroot 138038904Sborman #ifndef TCSIG 138138904Sborman # ifdef TIOCSIG 138238904Sborman # define TCSIG TIOCSIG 138338904Sborman # endif 138438904Sborman #endif 13856002Sroot 138657212Sdab #ifdef STREAMSPTY 138757212Sdab 138857212Sdab int flowison = -1; /* current state of flow: -1 is unknown */ 138957212Sdab 139057212Sdab int readstream(p, ibuf, bufsize) 139157212Sdab int p; 139257212Sdab char *ibuf; 139357212Sdab int bufsize; 139457212Sdab { 139557212Sdab int flags = 0; 139657212Sdab int ret = 0; 139757212Sdab struct termios *tsp; 139857212Sdab struct termio *tp; 139957212Sdab struct iocblk *ip; 140057212Sdab char vstop, vstart; 140157212Sdab int ixon; 140257212Sdab int newflow; 140357212Sdab 140457212Sdab strbufc.maxlen = BUFSIZ; 140565158Sdab strbufc.buf = (char *)ctlbuf; 140657212Sdab strbufd.maxlen = bufsize-1; 140757212Sdab strbufd.len = 0; 140857212Sdab strbufd.buf = ibuf+1; 140957212Sdab ibuf[0] = 0; 141057212Sdab 141157212Sdab ret = getmsg(p, &strbufc, &strbufd, &flags); 141257212Sdab if (ret < 0) /* error of some sort -- probably EAGAIN */ 141357212Sdab return(-1); 141457212Sdab 141557212Sdab if (strbufc.len <= 0 || ctlbuf[0] == M_DATA) { 141657212Sdab /* data message */ 141757212Sdab if (strbufd.len > 0) { /* real data */ 141857212Sdab return(strbufd.len + 1); /* count header char */ 141957212Sdab } else { 142057212Sdab /* nothing there */ 142157212Sdab errno = EAGAIN; 142257212Sdab return(-1); 142357212Sdab } 142457212Sdab } 142557212Sdab 142657212Sdab /* 142757212Sdab * It's a control message. Return 1, to look at the flag we set 142857212Sdab */ 142957212Sdab 143057212Sdab switch (ctlbuf[0]) { 143157212Sdab case M_FLUSH: 143257212Sdab if (ibuf[1] & FLUSHW) 143357212Sdab ibuf[0] = TIOCPKT_FLUSHWRITE; 143457212Sdab return(1); 143557212Sdab 143657212Sdab case M_IOCTL: 143757212Sdab ip = (struct iocblk *) (ibuf+1); 143857212Sdab 143957212Sdab switch (ip->ioc_cmd) { 144057212Sdab case TCSETS: 144157212Sdab case TCSETSW: 144257212Sdab case TCSETSF: 144357212Sdab tsp = (struct termios *) 144457212Sdab (ibuf+1 + sizeof(struct iocblk)); 144557212Sdab vstop = tsp->c_cc[VSTOP]; 144657212Sdab vstart = tsp->c_cc[VSTART]; 144757212Sdab ixon = tsp->c_iflag & IXON; 144857212Sdab break; 144957212Sdab case TCSETA: 145057212Sdab case TCSETAW: 145157212Sdab case TCSETAF: 145257212Sdab tp = (struct termio *) (ibuf+1 + sizeof(struct iocblk)); 145357212Sdab vstop = tp->c_cc[VSTOP]; 145457212Sdab vstart = tp->c_cc[VSTART]; 145557212Sdab ixon = tp->c_iflag & IXON; 145657212Sdab break; 145757212Sdab default: 145857212Sdab errno = EAGAIN; 145957212Sdab return(-1); 146057212Sdab } 146157212Sdab 146257212Sdab newflow = (ixon && (vstart == 021) && (vstop == 023)) ? 1 : 0; 146357212Sdab if (newflow != flowison) { /* it's a change */ 146457212Sdab flowison = newflow; 146557212Sdab ibuf[0] = newflow ? TIOCPKT_DOSTOP : TIOCPKT_NOSTOP; 146657212Sdab return(1); 146757212Sdab } 146857212Sdab } 146957212Sdab 147057212Sdab /* nothing worth doing anything about */ 147157212Sdab errno = EAGAIN; 147257212Sdab return(-1); 147357212Sdab } 147457212Sdab #endif /* STREAMSPTY */ 147557212Sdab 147637212Sminshall /* 14776002Sroot * Send interrupt to process on other side of pty. 14786002Sroot * If it is in raw mode, just write NULL; 14796002Sroot * otherwise, write intr char. 14806002Sroot */ 148146809Sdab void 14826002Sroot interrupt() 14836002Sroot { 148438904Sborman ptyflush(); /* half-hearted */ 14856002Sroot 1486*68346Sdab #if defined(STREAMSPTY) && defined(TIOCSIGNAL) 1487*68346Sdab /* Streams PTY style ioctl to post a signal */ 1488*68346Sdab { 1489*68346Sdab int sig = SIGINT; 1490*68346Sdab (void) ioctl(pty, TIOCSIGNAL, &sig); 1491*68346Sdab (void) ioctl(pty, I_FLUSH, FLUSHR); 1492*68346Sdab } 1493*68346Sdab #else 149438904Sborman #ifdef TCSIG 149538904Sborman (void) ioctl(pty, TCSIG, (char *)SIGINT); 149638904Sborman #else /* TCSIG */ 149738904Sborman init_termbuf(); 149840242Sborman *pfrontp++ = slctab[SLC_IP].sptr ? 149940242Sborman (unsigned char)*slctab[SLC_IP].sptr : '\177'; 150038904Sborman #endif /* TCSIG */ 1501*68346Sdab #endif 15026002Sroot } 15036002Sroot 150427229Sminshall /* 150527229Sminshall * Send quit to process on other side of pty. 150627229Sminshall * If it is in raw mode, just write NULL; 150727229Sminshall * otherwise, write quit char. 150827229Sminshall */ 150946809Sdab void 151027229Sminshall sendbrk() 151127229Sminshall { 151227229Sminshall ptyflush(); /* half-hearted */ 151338904Sborman #ifdef TCSIG 151438904Sborman (void) ioctl(pty, TCSIG, (char *)SIGQUIT); 151538904Sborman #else /* TCSIG */ 151638904Sborman init_termbuf(); 151740242Sborman *pfrontp++ = slctab[SLC_ABORT].sptr ? 151840242Sborman (unsigned char)*slctab[SLC_ABORT].sptr : '\034'; 151938904Sborman #endif /* TCSIG */ 152027229Sminshall } 152127229Sminshall 152246809Sdab void 152338904Sborman sendsusp() 15246002Sroot { 152538904Sborman #ifdef SIGTSTP 152638904Sborman ptyflush(); /* half-hearted */ 152738904Sborman # ifdef TCSIG 152838904Sborman (void) ioctl(pty, TCSIG, (char *)SIGTSTP); 152938904Sborman # else /* TCSIG */ 153040242Sborman *pfrontp++ = slctab[SLC_SUSP].sptr ? 153140242Sborman (unsigned char)*slctab[SLC_SUSP].sptr : '\032'; 153238904Sborman # endif /* TCSIG */ 153338904Sborman #endif /* SIGTSTP */ 15346002Sroot } 15356002Sroot 153645234Sborman /* 153745234Sborman * When we get an AYT, if ^T is enabled, use that. Otherwise, 153845234Sborman * just send back "[Yes]". 153945234Sborman */ 154046809Sdab void 154145234Sborman recv_ayt() 154245234Sborman { 154345234Sborman #if defined(SIGINFO) && defined(TCSIG) 154445234Sborman if (slctab[SLC_AYT].sptr && *slctab[SLC_AYT].sptr != _POSIX_VDISABLE) { 154545234Sborman (void) ioctl(pty, TCSIG, (char *)SIGINFO); 154645234Sborman return; 154745234Sborman } 154845234Sborman #endif 154945234Sborman (void) strcpy(nfrontp, "\r\n[Yes]\r\n"); 155045234Sborman nfrontp += 9; 155145234Sborman } 155245234Sborman 155346809Sdab void 155438904Sborman doeof() 15556002Sroot { 155638904Sborman init_termbuf(); 15576002Sroot 155845234Sborman #if defined(LINEMODE) && defined(USE_TERMIO) && (VEOF == VMIN) 155940242Sborman if (!tty_isediting()) { 156046809Sdab extern char oldeofc; 156140242Sborman *pfrontp++ = oldeofc; 156240242Sborman return; 156340242Sborman } 156440242Sborman #endif 156540242Sborman *pfrontp++ = slctab[SLC_EOF].sptr ? 156640242Sborman (unsigned char)*slctab[SLC_EOF].sptr : '\004'; 15676002Sroot } 1568