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*65158Sdab static char sccsid[] = "@(#)telnetd.c 8.2 (Berkeley) 12/15/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 */ 71*65158Sdab long ptyibufbuf[BUFSIZ/sizeof(long)+1]; 72*65158Sdab char *ptyibuf = ((char *)&ptyibufbuf[1])-1; 73*65158Sdab 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 */ 558*65158Sdab static unsigned char ttytype_sbbuf[] = { 559*65158Sdab IAC, SB, TELOPT_TTYPE, TELQUAL_SEND, IAC, SE 560*65158Sdab }; 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); 588*65158Sdab send_do(TELOPT_NEW_ENVIRON, 1); 589*65158Sdab 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) || 597*65158Sdab his_will_wont_is_changing(TELOPT_NEW_ENVIRON) || 598*65158Sdab 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)) { 611*65158Sdab static unsigned char sb[] = 612*65158Sdab { IAC, SB, TELOPT_TSPEED, TELQUAL_SEND, IAC, SE }; 61327983Sminshall 614*65158Sdab bcopy(sb, nfrontp, sizeof sb); 615*65158Sdab nfrontp += sizeof sb; 61638904Sborman } 61744363Sborman if (his_state_is_will(TELOPT_XDISPLOC)) { 618*65158Sdab static unsigned char sb[] = 619*65158Sdab { IAC, SB, TELOPT_XDISPLOC, TELQUAL_SEND, IAC, SE }; 62038904Sborman 621*65158Sdab bcopy(sb, nfrontp, sizeof sb); 622*65158Sdab nfrontp += sizeof sb; 62344363Sborman } 624*65158Sdab if (his_state_is_will(TELOPT_NEW_ENVIRON)) { 625*65158Sdab static unsigned char sb[] = 626*65158Sdab { IAC, SB, TELOPT_NEW_ENVIRON, TELQUAL_SEND, IAC, SE }; 62744363Sborman 628*65158Sdab bcopy(sb, nfrontp, sizeof sb); 629*65158Sdab nfrontp += sizeof sb; 63044363Sborman } 631*65158Sdab else if (his_state_is_will(TELOPT_OLD_ENVIRON)) { 632*65158Sdab static unsigned char sb[] = 633*65158Sdab { IAC, SB, TELOPT_OLD_ENVIRON, TELQUAL_SEND, IAC, SE }; 634*65158Sdab 635*65158Sdab bcopy(sb, nfrontp, sizeof sb); 636*65158Sdab nfrontp += sizeof sb; 637*65158Sdab } 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 } 651*65158Sdab if (his_state_is_will(TELOPT_NEW_ENVIRON)) { 65244363Sborman while (sequenceIs(environsubopt, baseline)) 65344363Sborman ttloop(); 65444363Sborman } 655*65158Sdab if (his_state_is_will(TELOPT_OLD_ENVIRON)) { 656*65158Sdab while (sequenceIs(oenvironsubopt, baseline)) 657*65158Sdab ttloop(); 658*65158Sdab } 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(); 90446809Sdab 90532400Sminshall /* 90638904Sborman * Initialize the slc mapping table. 90732400Sminshall */ 90838904Sborman get_slc_defaults(); 9096002Sroot 9108379Ssam /* 91138904Sborman * Do some tests where it is desireable to wait for a response. 91238904Sborman * Rather than doing them slowly, one at a time, do them all 91338904Sborman * at once. 9148379Ssam */ 91544363Sborman if (my_state_is_wont(TELOPT_SGA)) 91639503Sborman send_will(TELOPT_SGA, 1); 91712713Ssam /* 91827649Sminshall * Is the client side a 4.2 (NOT 4.3) system? We need to know this 91927649Sminshall * because 4.2 clients are unable to deal with TCP urgent data. 92027649Sminshall * 92127649Sminshall * To find out, we send out a "DO ECHO". If the remote system 92227649Sminshall * answers "WILL ECHO" it is probably a 4.2 client, and we note 92327649Sminshall * that fact ("WILL ECHO" ==> that the client will echo what 92427649Sminshall * WE, the server, sends it; it does NOT mean that the client will 92527649Sminshall * echo the terminal input). 92627649Sminshall */ 92739503Sborman send_do(TELOPT_ECHO, 1); 92827649Sminshall 92938904Sborman #ifdef LINEMODE 93044363Sborman if (his_state_is_wont(TELOPT_LINEMODE)) { 93138904Sborman /* Query the peer for linemode support by trying to negotiate 93238904Sborman * the linemode option. 93338904Sborman */ 93444363Sborman linemode = 0; 93538904Sborman editmode = 0; 93639503Sborman send_do(TELOPT_LINEMODE, 1); /* send do linemode */ 93738904Sborman } 93838904Sborman #endif /* LINEMODE */ 93938904Sborman 94027649Sminshall /* 94138904Sborman * Send along a couple of other options that we wish to negotiate. 94238904Sborman */ 94339503Sborman send_do(TELOPT_NAWS, 1); 94439503Sborman send_will(TELOPT_STATUS, 1); 94557597Sdab flowmode = 1; /* default flow control state */ 94657597Sdab restartany = -1; /* uninitialized... */ 94739503Sborman send_do(TELOPT_LFLOW, 1); 94838904Sborman 94938904Sborman /* 95038904Sborman * Spin, waiting for a response from the DO ECHO. However, 95138904Sborman * some REALLY DUMB telnets out there might not respond 95238904Sborman * to the DO ECHO. So, we spin looking for NAWS, (most dumb 95338904Sborman * telnets so far seem to respond with WONT for a DO that 95438904Sborman * they don't understand...) because by the time we get the 95538904Sborman * response, it will already have processed the DO ECHO. 95638904Sborman * Kludge upon kludge. 95738904Sborman */ 95844363Sborman while (his_will_wont_is_changing(TELOPT_NAWS)) 95938904Sborman ttloop(); 96038904Sborman 96138904Sborman /* 96244363Sborman * But... 96344363Sborman * The client might have sent a WILL NAWS as part of its 96444363Sborman * startup code; if so, we'll be here before we get the 96544363Sborman * response to the DO ECHO. We'll make the assumption 96644363Sborman * that any implementation that understands about NAWS 96744363Sborman * is a modern enough implementation that it will respond 96844363Sborman * to our DO ECHO request; hence we'll do another spin 96944363Sborman * waiting for the ECHO option to settle down, which is 97044363Sborman * what we wanted to do in the first place... 97144363Sborman */ 97244363Sborman if (his_want_state_is_will(TELOPT_ECHO) && 97344363Sborman his_state_is_will(TELOPT_NAWS)) { 97444363Sborman while (his_will_wont_is_changing(TELOPT_ECHO)) 97544363Sborman ttloop(); 97644363Sborman } 97744363Sborman /* 97838995Sborman * On the off chance that the telnet client is broken and does not 97938995Sborman * respond to the DO ECHO we sent, (after all, we did send the 98038995Sborman * DO NAWS negotiation after the DO ECHO, and we won't get here 98138995Sborman * until a response to the DO NAWS comes back) simulate the 98238995Sborman * receipt of a will echo. This will also send a WONT ECHO 98338995Sborman * to the client, since we assume that the client failed to 98438995Sborman * respond because it believes that it is already in DO ECHO 98538995Sborman * mode, which we do not want. 98638995Sborman */ 98744363Sborman if (his_want_state_is_will(TELOPT_ECHO)) { 98846809Sdab DIAG(TD_OPTIONS, 98946809Sdab {sprintf(nfrontp, "td: simulating recv\r\n"); 99046809Sdab nfrontp += strlen(nfrontp);}); 99139503Sborman willoption(TELOPT_ECHO); 99240242Sborman } 99338995Sborman 99438995Sborman /* 99538995Sborman * Finally, to clean things up, we turn on our echo. This 99638995Sborman * will break stupid 4.2 telnets out of local terminal echo. 99738995Sborman */ 99838995Sborman 99944363Sborman if (my_state_is_wont(TELOPT_ECHO)) 100039503Sborman send_will(TELOPT_ECHO, 1); 100138995Sborman 100257212Sdab #ifndef STREAMSPTY 100338995Sborman /* 100445234Sborman * Turn on packet mode 100538904Sborman */ 100638904Sborman (void) ioctl(p, TIOCPKT, (char *)&on); 100757212Sdab #endif 100857212Sdab 100946809Sdab #if defined(LINEMODE) && defined(KLUDGELINEMODE) 101038904Sborman /* 101138904Sborman * Continuing line mode support. If client does not support 101238904Sborman * real linemode, attempt to negotiate kludge linemode by sending 101338904Sborman * the do timing mark sequence. 101438904Sborman */ 101538904Sborman if (lmodetype < REAL_LINEMODE) 101639503Sborman send_do(TELOPT_TM, 1); 101746809Sdab #endif /* defined(LINEMODE) && defined(KLUDGELINEMODE) */ 101838904Sborman 101938904Sborman /* 102038904Sborman * Call telrcv() once to pick up anything received during 102138904Sborman * terminal type negotiation, 4.2/4.3 determination, and 102238904Sborman * linemode negotiation. 102338904Sborman */ 102438904Sborman telrcv(); 102538904Sborman 102638904Sborman (void) ioctl(f, FIONBIO, (char *)&on); 102738904Sborman (void) ioctl(p, FIONBIO, (char *)&on); 102840242Sborman #if defined(CRAY2) && defined(UNICOS5) 102938904Sborman init_termdriver(f, p, interrupt, sendbrk); 103038904Sborman #endif 103138904Sborman 103238904Sborman #if defined(SO_OOBINLINE) 103357212Sdab (void) setsockopt(net, SOL_SOCKET, SO_OOBINLINE, 103457212Sdab (char *)&on, sizeof on); 103538904Sborman #endif /* defined(SO_OOBINLINE) */ 103638904Sborman 103738904Sborman #ifdef SIGTSTP 103838904Sborman (void) signal(SIGTSTP, SIG_IGN); 103938904Sborman #endif 104038904Sborman #ifdef SIGTTOU 104138904Sborman /* 104238904Sborman * Ignoring SIGTTOU keeps the kernel from blocking us 104338904Sborman * in ttioct() in /sys/tty.c. 104438904Sborman */ 104538904Sborman (void) signal(SIGTTOU, SIG_IGN); 104638904Sborman #endif 104738904Sborman 104838904Sborman (void) signal(SIGCHLD, cleanup); 104938904Sborman 105040242Sborman #if defined(CRAY2) && defined(UNICOS5) 105138904Sborman /* 105238904Sborman * Cray-2 will send a signal when pty modes are changed by slave 105338904Sborman * side. Set up signal handler now. 105438904Sborman */ 105538904Sborman if ((int)signal(SIGUSR1, termstat) < 0) 105638904Sborman perror("signal"); 105738904Sborman else if (ioctl(p, TCSIGME, (char *)SIGUSR1) < 0) 105838904Sborman perror("ioctl:TCSIGME"); 105938904Sborman /* 106038904Sborman * Make processing loop check terminal characteristics early on. 106138904Sborman */ 106238904Sborman termstat(); 106338904Sborman #endif 106438904Sborman 106545234Sborman #ifdef TIOCNOTTY 106645234Sborman { 106745234Sborman register int t; 106845234Sborman t = open(_PATH_TTY, O_RDWR); 106945234Sborman if (t >= 0) { 107045234Sborman (void) ioctl(t, TIOCNOTTY, (char *)0); 107145234Sborman (void) close(t); 107245234Sborman } 107345234Sborman } 107440242Sborman #endif 107545234Sborman 107646809Sdab #if defined(CRAY) && defined(NEWINIT) && defined(TIOCSCTTY) 107745234Sborman (void) setsid(); 107844363Sborman ioctl(p, TIOCSCTTY, 0); 107944363Sborman #endif 108038904Sborman 108138904Sborman /* 108212713Ssam * Show banner that getty never gave. 108327797Sminshall * 108433271Sminshall * We put the banner in the pty input buffer. This way, it 108533271Sminshall * gets carriage return null processing, etc., just like all 108633271Sminshall * other pty --> client data. 108712713Ssam */ 108827797Sminshall 108945234Sborman #if !defined(CRAY) || !defined(NEWINIT) 109045234Sborman if (getenv("USER")) 109145234Sborman hostinfo = 0; 109245234Sborman #endif 109338904Sborman 109433271Sminshall if (getent(defent, "default") == 1) { 109533271Sminshall char *getstr(); 109638904Sborman char *cp=defstrs; 109727649Sminshall 109838904Sborman HE = getstr("he", &cp); 109938904Sborman HN = getstr("hn", &cp); 110038904Sborman IM = getstr("im", &cp); 110133271Sminshall if (HN && *HN) 110246809Sdab (void) strcpy(host_name, HN); 110338904Sborman if (IM == 0) 110438904Sborman IM = ""; 110533271Sminshall } else { 110645234Sborman IM = DEFAULT_IM; 110738904Sborman HE = 0; 110833271Sminshall } 110946809Sdab edithost(HE, host_name); 111045234Sborman if (hostinfo && *IM) 111138904Sborman putf(IM, ptyibuf2); 111227797Sminshall 111338904Sborman if (pcc) 111438904Sborman (void) strncat(ptyibuf2, ptyip, pcc+1); 111538904Sborman ptyip = ptyibuf2; 111638904Sborman pcc = strlen(ptyip); 111740242Sborman #ifdef LINEMODE 111840242Sborman /* 111940242Sborman * Last check to make sure all our states are correct. 112040242Sborman */ 112140242Sborman init_termbuf(); 112240242Sborman localstat(); 112340242Sborman #endif /* LINEMODE */ 112433271Sminshall 112546809Sdab DIAG(TD_REPORT, 112646809Sdab {sprintf(nfrontp, "td: Entering processing loop\r\n"); 112746809Sdab nfrontp += strlen(nfrontp);}); 112844363Sborman 112945234Sborman #ifdef convex 113045234Sborman startslave(host); 113145234Sborman #endif 113245234Sborman 11336002Sroot for (;;) { 113427185Sminshall fd_set ibits, obits, xbits; 11356002Sroot register int c; 11366002Sroot 113727185Sminshall if (ncc < 0 && pcc < 0) 113827185Sminshall break; 113927185Sminshall 114040242Sborman #if defined(CRAY2) && defined(UNICOS5) 114138904Sborman if (needtermstat) 114238904Sborman _termstat(); 114340242Sborman #endif /* defined(CRAY2) && defined(UNICOS5) */ 114427185Sminshall FD_ZERO(&ibits); 114527185Sminshall FD_ZERO(&obits); 114627185Sminshall FD_ZERO(&xbits); 11476002Sroot /* 11486002Sroot * Never look for input if there's still 11496002Sroot * stuff in the corresponding output buffer 11506002Sroot */ 115127185Sminshall if (nfrontp - nbackp || pcc > 0) { 115227185Sminshall FD_SET(f, &obits); 115327185Sminshall } else { 115427185Sminshall FD_SET(p, &ibits); 115527185Sminshall } 115627185Sminshall if (pfrontp - pbackp || ncc > 0) { 115727185Sminshall FD_SET(p, &obits); 115827185Sminshall } else { 115927185Sminshall FD_SET(f, &ibits); 116027185Sminshall } 116127185Sminshall if (!SYNCHing) { 116227185Sminshall FD_SET(f, &xbits); 116327185Sminshall } 116427185Sminshall if ((c = select(16, &ibits, &obits, &xbits, 116527185Sminshall (struct timeval *)0)) < 1) { 116627185Sminshall if (c == -1) { 116727185Sminshall if (errno == EINTR) { 116827185Sminshall continue; 116927185Sminshall } 117027185Sminshall } 11716002Sroot sleep(5); 11726002Sroot continue; 11736002Sroot } 11746002Sroot 11756002Sroot /* 117627185Sminshall * Any urgent data? 117727185Sminshall */ 117827185Sminshall if (FD_ISSET(net, &xbits)) { 117927185Sminshall SYNCHing = 1; 118027185Sminshall } 118127185Sminshall 118227185Sminshall /* 11836002Sroot * Something to read from the network... 11846002Sroot */ 118527185Sminshall if (FD_ISSET(net, &ibits)) { 118627649Sminshall #if !defined(SO_OOBINLINE) 118727185Sminshall /* 118827898Skarels * In 4.2 (and 4.3 beta) systems, the 118927185Sminshall * OOB indication and data handling in the kernel 119027185Sminshall * is such that if two separate TCP Urgent requests 119127185Sminshall * come in, one byte of TCP data will be overlaid. 119227185Sminshall * This is fatal for Telnet, but we try to live 119327185Sminshall * with it. 119427185Sminshall * 119527185Sminshall * In addition, in 4.2 (and...), a special protocol 119627185Sminshall * is needed to pick up the TCP Urgent data in 119727185Sminshall * the correct sequence. 119827185Sminshall * 119927185Sminshall * What we do is: if we think we are in urgent 120027185Sminshall * mode, we look to see if we are "at the mark". 120127185Sminshall * If we are, we do an OOB receive. If we run 120227185Sminshall * this twice, we will do the OOB receive twice, 120327185Sminshall * but the second will fail, since the second 120427185Sminshall * time we were "at the mark", but there wasn't 120527185Sminshall * any data there (the kernel doesn't reset 120627185Sminshall * "at the mark" until we do a normal read). 120727185Sminshall * Once we've read the OOB data, we go ahead 120827185Sminshall * and do normal reads. 120927185Sminshall * 121027185Sminshall * There is also another problem, which is that 121127185Sminshall * since the OOB byte we read doesn't put us 121227185Sminshall * out of OOB state, and since that byte is most 121327185Sminshall * likely the TELNET DM (data mark), we would 121427185Sminshall * stay in the TELNET SYNCH (SYNCHing) state. 121527185Sminshall * So, clocks to the rescue. If we've "just" 121627185Sminshall * received a DM, then we test for the 121727185Sminshall * presence of OOB data when the receive OOB 121827185Sminshall * fails (and AFTER we did the normal mode read 121927185Sminshall * to clear "at the mark"). 122027185Sminshall */ 122127185Sminshall if (SYNCHing) { 122227185Sminshall int atmark; 122327185Sminshall 122438904Sborman (void) ioctl(net, SIOCATMARK, (char *)&atmark); 122527185Sminshall if (atmark) { 122627185Sminshall ncc = recv(net, netibuf, sizeof (netibuf), MSG_OOB); 122727185Sminshall if ((ncc == -1) && (errno == EINVAL)) { 122827185Sminshall ncc = read(net, netibuf, sizeof (netibuf)); 122927983Sminshall if (sequenceIs(didnetreceive, gotDM)) { 123027185Sminshall SYNCHing = stilloob(net); 123127185Sminshall } 123227185Sminshall } 123327185Sminshall } else { 123427185Sminshall ncc = read(net, netibuf, sizeof (netibuf)); 12356002Sroot } 123627185Sminshall } else { 123727185Sminshall ncc = read(net, netibuf, sizeof (netibuf)); 123827185Sminshall } 123927185Sminshall settimer(didnetreceive); 124027649Sminshall #else /* !defined(SO_OOBINLINE)) */ 124127185Sminshall ncc = read(net, netibuf, sizeof (netibuf)); 124227649Sminshall #endif /* !defined(SO_OOBINLINE)) */ 124327185Sminshall if (ncc < 0 && errno == EWOULDBLOCK) 124427185Sminshall ncc = 0; 124527185Sminshall else { 124627185Sminshall if (ncc <= 0) { 124727185Sminshall break; 124827185Sminshall } 124927185Sminshall netip = netibuf; 125027185Sminshall } 125146809Sdab DIAG((TD_REPORT | TD_NETDATA), 125246809Sdab {sprintf(nfrontp, "td: netread %d chars\r\n", ncc); 125346809Sdab nfrontp += strlen(nfrontp);}); 125446809Sdab DIAG(TD_NETDATA, printdata("nd", netip, ncc)); 12556002Sroot } 12566002Sroot 12576002Sroot /* 12586002Sroot * Something to read from the pty... 12596002Sroot */ 126038904Sborman if (FD_ISSET(p, &ibits)) { 126157212Sdab #ifndef STREAMSPTY 12626002Sroot pcc = read(p, ptyibuf, BUFSIZ); 126357212Sdab #else 126457212Sdab pcc = readstream(p, ptyibuf, BUFSIZ); 126557212Sdab #endif 126646809Sdab /* 126746809Sdab * On some systems, if we try to read something 126846809Sdab * off the master side before the slave side is 126946809Sdab * opened, we get EIO. 127046809Sdab */ 127157212Sdab if (pcc < 0 && (errno == EWOULDBLOCK || 127257212Sdab #ifdef EAGAIN 127357212Sdab errno == EAGAIN || 127457212Sdab #endif 127557212Sdab errno == EIO)) { 12766002Sroot pcc = 0; 127746809Sdab } else { 12786002Sroot if (pcc <= 0) 12796002Sroot break; 128040242Sborman #if !defined(CRAY2) || !defined(UNICOS5) 128138904Sborman #ifdef LINEMODE 128238904Sborman /* 128338904Sborman * If ioctl from pty, pass it through net 128438904Sborman */ 128538904Sborman if (ptyibuf[0] & TIOCPKT_IOCTL) { 128638904Sborman copy_termbuf(ptyibuf+1, pcc-1); 128738904Sborman localstat(); 128838904Sborman pcc = 1; 128938904Sborman } 129046809Sdab #endif /* LINEMODE */ 129137210Sminshall if (ptyibuf[0] & TIOCPKT_FLUSHWRITE) { 129238904Sborman netclear(); /* clear buffer back */ 129345234Sborman #ifndef NO_URGENT 129440242Sborman /* 129545234Sborman * There are client telnets on some 129640242Sborman * operating systems get screwed up 129740242Sborman * royally if we send them urgent 129845234Sborman * mode data. 129940242Sborman */ 130037210Sminshall *nfrontp++ = IAC; 130137210Sminshall *nfrontp++ = DM; 130237210Sminshall neturg = nfrontp-1; /* off by one XXX */ 130340242Sborman #endif 130437210Sminshall } 130544363Sborman if (his_state_is_will(TELOPT_LFLOW) && 130637210Sminshall (ptyibuf[0] & 130738904Sborman (TIOCPKT_NOSTOP|TIOCPKT_DOSTOP))) { 130857597Sdab int newflow = 130957597Sdab ptyibuf[0] & TIOCPKT_DOSTOP ? 1 : 0; 131057597Sdab if (newflow != flowmode) { 131157597Sdab flowmode = newflow; 131257597Sdab (void) sprintf(nfrontp, 131357597Sdab "%c%c%c%c%c%c", 131457597Sdab IAC, SB, TELOPT_LFLOW, 131557597Sdab flowmode ? LFLOW_ON 131657597Sdab : LFLOW_OFF, 131757597Sdab IAC, SE); 131857597Sdab nfrontp += 6; 131957597Sdab } 132037210Sminshall } 132133267Sminshall pcc--; 132233267Sminshall ptyip = ptyibuf+1; 132340242Sborman #else /* defined(CRAY2) && defined(UNICOS5) */ 132438904Sborman if (!uselinemode) { 132539531Sborman unpcc = pcc; 132639531Sborman unptyip = ptyibuf; 132739531Sborman pcc = term_output(&unptyip, ptyibuf2, 132839531Sborman &unpcc, BUFSIZ); 132938904Sborman ptyip = ptyibuf2; 133038904Sborman } else 133138904Sborman ptyip = ptyibuf; 133240242Sborman #endif /* defined(CRAY2) && defined(UNICOS5) */ 133338904Sborman } 13346002Sroot } 13356002Sroot 13366002Sroot while (pcc > 0) { 13376002Sroot if ((&netobuf[BUFSIZ] - nfrontp) < 2) 13386002Sroot break; 13396002Sroot c = *ptyip++ & 0377, pcc--; 13406002Sroot if (c == IAC) 13416002Sroot *nfrontp++ = c; 134240242Sborman #if defined(CRAY2) && defined(UNICOS5) 134338904Sborman else if (c == '\n' && 134444363Sborman my_state_is_wont(TELOPT_BINARY) && newmap) 134538904Sborman *nfrontp++ = '\r'; 134640242Sborman #endif /* defined(CRAY2) && defined(UNICOS5) */ 13476002Sroot *nfrontp++ = c; 134844363Sborman if ((c == '\r') && (my_state_is_wont(TELOPT_BINARY))) { 134927020Sminshall if (pcc > 0 && ((*ptyip & 0377) == '\n')) { 135027020Sminshall *nfrontp++ = *ptyip++ & 0377; 135127020Sminshall pcc--; 135227020Sminshall } else 135327020Sminshall *nfrontp++ = '\0'; 135427020Sminshall } 13556002Sroot } 135640242Sborman #if defined(CRAY2) && defined(UNICOS5) 135739531Sborman /* 135839531Sborman * If chars were left over from the terminal driver, 135939531Sborman * note their existence. 136039531Sborman */ 136146809Sdab if (!uselinemode && unpcc) { 136239531Sborman pcc = unpcc; 136339531Sborman unpcc = 0; 136439531Sborman ptyip = unptyip; 136539531Sborman } 136640242Sborman #endif /* defined(CRAY2) && defined(UNICOS5) */ 136739531Sborman 136827185Sminshall if (FD_ISSET(f, &obits) && (nfrontp - nbackp) > 0) 13696002Sroot netflush(); 13706002Sroot if (ncc > 0) 13716002Sroot telrcv(); 137227185Sminshall if (FD_ISSET(p, &obits) && (pfrontp - pbackp) > 0) 13736002Sroot ptyflush(); 13746002Sroot } 137546809Sdab cleanup(0); 137638904Sborman } /* end of telnet */ 13776002Sroot 137838904Sborman #ifndef TCSIG 137938904Sborman # ifdef TIOCSIG 138038904Sborman # define TCSIG TIOCSIG 138138904Sborman # endif 138238904Sborman #endif 13836002Sroot 138457212Sdab #ifdef STREAMSPTY 138557212Sdab 138657212Sdab int flowison = -1; /* current state of flow: -1 is unknown */ 138757212Sdab 138857212Sdab int readstream(p, ibuf, bufsize) 138957212Sdab int p; 139057212Sdab char *ibuf; 139157212Sdab int bufsize; 139257212Sdab { 139357212Sdab int flags = 0; 139457212Sdab int ret = 0; 139557212Sdab struct termios *tsp; 139657212Sdab struct termio *tp; 139757212Sdab struct iocblk *ip; 139857212Sdab char vstop, vstart; 139957212Sdab int ixon; 140057212Sdab int newflow; 140157212Sdab 140257212Sdab strbufc.maxlen = BUFSIZ; 1403*65158Sdab strbufc.buf = (char *)ctlbuf; 140457212Sdab strbufd.maxlen = bufsize-1; 140557212Sdab strbufd.len = 0; 140657212Sdab strbufd.buf = ibuf+1; 140757212Sdab ibuf[0] = 0; 140857212Sdab 140957212Sdab ret = getmsg(p, &strbufc, &strbufd, &flags); 141057212Sdab if (ret < 0) /* error of some sort -- probably EAGAIN */ 141157212Sdab return(-1); 141257212Sdab 141357212Sdab if (strbufc.len <= 0 || ctlbuf[0] == M_DATA) { 141457212Sdab /* data message */ 141557212Sdab if (strbufd.len > 0) { /* real data */ 141657212Sdab return(strbufd.len + 1); /* count header char */ 141757212Sdab } else { 141857212Sdab /* nothing there */ 141957212Sdab errno = EAGAIN; 142057212Sdab return(-1); 142157212Sdab } 142257212Sdab } 142357212Sdab 142457212Sdab /* 142557212Sdab * It's a control message. Return 1, to look at the flag we set 142657212Sdab */ 142757212Sdab 142857212Sdab switch (ctlbuf[0]) { 142957212Sdab case M_FLUSH: 143057212Sdab if (ibuf[1] & FLUSHW) 143157212Sdab ibuf[0] = TIOCPKT_FLUSHWRITE; 143257212Sdab return(1); 143357212Sdab 143457212Sdab case M_IOCTL: 143557212Sdab ip = (struct iocblk *) (ibuf+1); 143657212Sdab 143757212Sdab switch (ip->ioc_cmd) { 143857212Sdab case TCSETS: 143957212Sdab case TCSETSW: 144057212Sdab case TCSETSF: 144157212Sdab tsp = (struct termios *) 144257212Sdab (ibuf+1 + sizeof(struct iocblk)); 144357212Sdab vstop = tsp->c_cc[VSTOP]; 144457212Sdab vstart = tsp->c_cc[VSTART]; 144557212Sdab ixon = tsp->c_iflag & IXON; 144657212Sdab break; 144757212Sdab case TCSETA: 144857212Sdab case TCSETAW: 144957212Sdab case TCSETAF: 145057212Sdab tp = (struct termio *) (ibuf+1 + sizeof(struct iocblk)); 145157212Sdab vstop = tp->c_cc[VSTOP]; 145257212Sdab vstart = tp->c_cc[VSTART]; 145357212Sdab ixon = tp->c_iflag & IXON; 145457212Sdab break; 145557212Sdab default: 145657212Sdab errno = EAGAIN; 145757212Sdab return(-1); 145857212Sdab } 145957212Sdab 146057212Sdab newflow = (ixon && (vstart == 021) && (vstop == 023)) ? 1 : 0; 146157212Sdab if (newflow != flowison) { /* it's a change */ 146257212Sdab flowison = newflow; 146357212Sdab ibuf[0] = newflow ? TIOCPKT_DOSTOP : TIOCPKT_NOSTOP; 146457212Sdab return(1); 146557212Sdab } 146657212Sdab } 146757212Sdab 146857212Sdab /* nothing worth doing anything about */ 146957212Sdab errno = EAGAIN; 147057212Sdab return(-1); 147157212Sdab } 147257212Sdab #endif /* STREAMSPTY */ 147357212Sdab 147437212Sminshall /* 14756002Sroot * Send interrupt to process on other side of pty. 14766002Sroot * If it is in raw mode, just write NULL; 14776002Sroot * otherwise, write intr char. 14786002Sroot */ 147946809Sdab void 14806002Sroot interrupt() 14816002Sroot { 148238904Sborman ptyflush(); /* half-hearted */ 14836002Sroot 148438904Sborman #ifdef TCSIG 148538904Sborman (void) ioctl(pty, TCSIG, (char *)SIGINT); 148638904Sborman #else /* TCSIG */ 148738904Sborman init_termbuf(); 148840242Sborman *pfrontp++ = slctab[SLC_IP].sptr ? 148940242Sborman (unsigned char)*slctab[SLC_IP].sptr : '\177'; 149038904Sborman #endif /* TCSIG */ 14916002Sroot } 14926002Sroot 149327229Sminshall /* 149427229Sminshall * Send quit to process on other side of pty. 149527229Sminshall * If it is in raw mode, just write NULL; 149627229Sminshall * otherwise, write quit char. 149727229Sminshall */ 149846809Sdab void 149927229Sminshall sendbrk() 150027229Sminshall { 150127229Sminshall ptyflush(); /* half-hearted */ 150238904Sborman #ifdef TCSIG 150338904Sborman (void) ioctl(pty, TCSIG, (char *)SIGQUIT); 150438904Sborman #else /* TCSIG */ 150538904Sborman init_termbuf(); 150640242Sborman *pfrontp++ = slctab[SLC_ABORT].sptr ? 150740242Sborman (unsigned char)*slctab[SLC_ABORT].sptr : '\034'; 150838904Sborman #endif /* TCSIG */ 150927229Sminshall } 151027229Sminshall 151146809Sdab void 151238904Sborman sendsusp() 15136002Sroot { 151438904Sborman #ifdef SIGTSTP 151538904Sborman ptyflush(); /* half-hearted */ 151638904Sborman # ifdef TCSIG 151738904Sborman (void) ioctl(pty, TCSIG, (char *)SIGTSTP); 151838904Sborman # else /* TCSIG */ 151940242Sborman *pfrontp++ = slctab[SLC_SUSP].sptr ? 152040242Sborman (unsigned char)*slctab[SLC_SUSP].sptr : '\032'; 152138904Sborman # endif /* TCSIG */ 152238904Sborman #endif /* SIGTSTP */ 15236002Sroot } 15246002Sroot 152545234Sborman /* 152645234Sborman * When we get an AYT, if ^T is enabled, use that. Otherwise, 152745234Sborman * just send back "[Yes]". 152845234Sborman */ 152946809Sdab void 153045234Sborman recv_ayt() 153145234Sborman { 153245234Sborman #if defined(SIGINFO) && defined(TCSIG) 153345234Sborman if (slctab[SLC_AYT].sptr && *slctab[SLC_AYT].sptr != _POSIX_VDISABLE) { 153445234Sborman (void) ioctl(pty, TCSIG, (char *)SIGINFO); 153545234Sborman return; 153645234Sborman } 153745234Sborman #endif 153845234Sborman (void) strcpy(nfrontp, "\r\n[Yes]\r\n"); 153945234Sborman nfrontp += 9; 154045234Sborman } 154145234Sborman 154246809Sdab void 154338904Sborman doeof() 15446002Sroot { 154538904Sborman init_termbuf(); 15466002Sroot 154745234Sborman #if defined(LINEMODE) && defined(USE_TERMIO) && (VEOF == VMIN) 154840242Sborman if (!tty_isediting()) { 154946809Sdab extern char oldeofc; 155040242Sborman *pfrontp++ = oldeofc; 155140242Sborman return; 155240242Sborman } 155340242Sborman #endif 155440242Sborman *pfrontp++ = slctab[SLC_EOF].sptr ? 155540242Sborman (unsigned char)*slctab[SLC_EOF].sptr : '\004'; 15566002Sroot } 1557