121182Sdist /* 238904Sborman * Copyright (c) 1989 Regents of the University of California. 333687Sbostic * All rights reserved. 433687Sbostic * 5*42673Sbostic * %sccs.include.redist.c% 621182Sdist */ 721182Sdist 86295Sroot #ifndef lint 921182Sdist char copyright[] = 1038904Sborman "@(#) Copyright (c) 1989 Regents of the University of California.\n\ 1121182Sdist All rights reserved.\n"; 1233687Sbostic #endif /* not lint */ 136295Sroot 1421182Sdist #ifndef lint 15*42673Sbostic static char sccsid[] = "@(#)telnetd.c 5.43 (Berkeley) 06/01/90"; 1633687Sbostic #endif /* not lint */ 1721182Sdist 1838904Sborman #include "telnetd.h" 1938904Sborman 206002Sroot /* 2138904Sborman * I/O data buffers, 2238904Sborman * pointers, and counters. 236002Sroot */ 2438904Sborman char ptyibuf[BUFSIZ], *ptyip = ptyibuf; 2538904Sborman char ptyibuf2[BUFSIZ]; 269218Ssam 2738904Sborman #ifdef CRAY 2838904Sborman int hostinfo = 1; /* do we print login banner? */ 2938904Sborman #endif 309218Ssam 3138904Sborman #ifdef CRAY 3238904Sborman extern int newmap; /* nonzero if \n maps to ^M^J */ 3340242Sborman int lowpty = 0, highpty; /* low, high pty numbers */ 3438904Sborman #endif /* CRAY */ 3512216Ssam 3638904Sborman int debug = 0; 3738904Sborman char *progname; 389218Ssam 3940242Sborman #if defined(IP_TOS) && defined(NEED_GETTOS) 4040242Sborman struct tosent { 4140242Sborman char *t_name; /* name */ 4240242Sborman char **t_aliases; /* alias list */ 4340242Sborman char *t_proto; /* protocol */ 4440242Sborman int t_tos; /* Type Of Service bits */ 4540242Sborman }; 4640242Sborman 4740242Sborman struct tosent * 4840242Sborman gettosbyname(name, proto) 4940242Sborman char *name, *proto; 5040242Sborman { 5140242Sborman static struct tosent te; 5240242Sborman static char *aliasp = 0; 5340242Sborman 5440242Sborman te.t_name = name; 5540242Sborman te.t_aliases = &aliasp; 5640242Sborman te.t_proto = proto; 5740242Sborman te.t_tos = 020; /* Low Delay bit */ 5840242Sborman return(&te); 5940242Sborman } 6040242Sborman #endif 6140242Sborman 6238904Sborman main(argc, argv) 6338904Sborman char *argv[]; 6438904Sborman { 6538904Sborman struct sockaddr_in from; 6638904Sborman int on = 1, fromlen; 6740242Sborman #ifdef IP_TOS 6840242Sborman struct tosent *tp; 6940242Sborman #endif /* IP_TOS */ 706002Sroot 7138904Sborman pfrontp = pbackp = ptyobuf; 7238904Sborman netip = netibuf; 7338904Sborman nfrontp = nbackp = netobuf; 746002Sroot 7538904Sborman progname = *argv; 7640242Sborman 7740242Sborman #ifdef CRAY 7840242Sborman /* 7940242Sborman * Get number of pty's before trying to process options, 8040242Sborman * which may include changing pty range. 8140242Sborman */ 8240242Sborman highpty = getnpty(); 8340242Sborman #endif /* CRAY */ 8440242Sborman 8538904Sborman top: 8638904Sborman argc--, argv++; 8727649Sminshall 8838904Sborman if (argc > 0 && strcmp(*argv, "-debug") == 0) { 8938904Sborman debug++; 9038904Sborman goto top; 9138904Sborman } 9227649Sminshall 9338904Sborman #ifdef LINEMODE 9438904Sborman if (argc > 0 && !strcmp(*argv, "-l")) { 9538904Sborman alwayslinemode = 1; 9638904Sborman goto top; 9738904Sborman } 9838904Sborman #endif /* LINEMODE */ 9927649Sminshall 10038904Sborman #ifdef CRAY 10138904Sborman if (argc > 0 && !strcmp(*argv, "-h")) { 10238904Sborman hostinfo = 0; 10338904Sborman goto top; 10438904Sborman } 10527649Sminshall 10638904Sborman if (argc > 0 && !strncmp(*argv, "-r", 2)) { 10738904Sborman char *strchr(); 10838904Sborman char *c; 10927649Sminshall 11040242Sborman /* 11140242Sborman * Allow the specification of alterations to the pty search 11240242Sborman * range. It is legal to specify only one, and not change the 11340242Sborman * other from its default. 11440242Sborman */ 11538904Sborman *argv += 2; 11638904Sborman if (**argv == '\0' && argc) 11738904Sborman argv++, argc--; 11838904Sborman c = strchr(*argv, '-'); 11938904Sborman if (c) { 12038904Sborman *c++ = '\0'; 12138904Sborman highpty = atoi(c); 12240242Sborman } 12340242Sborman if (**argv != '\0') 12440242Sborman lowpty = atoi(*argv); 12540242Sborman if ((lowpty > highpty) || (lowpty < 0) || (highpty > 32767)) { 12638904Sborman usage: 12738904Sborman fprintf(stderr, "Usage: telnetd [-debug] [-h] "); 12838904Sborman # ifdef NEWINIT 12938904Sborman fprintf(stderr, "[-Iinitid] "); 13038904Sborman # endif /* NEWINIT */ 13140242Sborman fprintf(stderr, "[-l] [-r[lowpty]-[highpty]] [port]\n"); 13238904Sborman exit(1); 13338904Sborman } 13438904Sborman goto top; 13538904Sborman } 13638904Sborman # ifdef NEWINIT 13738904Sborman if (argc > 0 && !strncmp(*argv, "-I", 2)) { 13838904Sborman extern char *gen_id; 13927649Sminshall 14038904Sborman *argv += 2; 14138904Sborman if (**argv == '\0') { 14238904Sborman if (argc < 2) 14338904Sborman goto usage; 14438904Sborman argv++, argc--; 14538904Sborman if (**argv == '\0') 14638904Sborman goto usage; 14738904Sborman } 14838904Sborman gen_id = *argv; 14938904Sborman goto top; 15038904Sborman } 15138904Sborman # endif /* NEWINIT */ 15238904Sborman #endif /* CRAY */ 1536002Sroot 15438904Sborman if (debug) { 15527185Sminshall int s, ns, foo; 15627185Sminshall struct servent *sp; 15727185Sminshall static struct sockaddr_in sin = { AF_INET }; 15827185Sminshall 15938904Sborman if (argc > 0) { 16038904Sborman if (sp = getservbyname(*argv, "tcp")) { 16138904Sborman sin.sin_port = sp->s_port; 16238904Sborman } else { 16338904Sborman sin.sin_port = atoi(*argv); 16438904Sborman if ((int)sin.sin_port <= 0) { 16538904Sborman fprintf(stderr, "telnetd: %s: bad port #\n", *argv); 16638904Sborman exit(1); 16738904Sborman } 16838904Sborman sin.sin_port = htons((u_short)sin.sin_port); 16938904Sborman } 17037210Sminshall } else { 17137210Sminshall sp = getservbyname("telnet", "tcp"); 17237210Sminshall if (sp == 0) { 17337210Sminshall fprintf(stderr, 17437210Sminshall "telnetd: tcp/telnet: unknown service\n"); 17538904Sborman exit(1); 17637210Sminshall } 17737210Sminshall sin.sin_port = sp->s_port; 17827185Sminshall } 17927185Sminshall 18027185Sminshall s = socket(AF_INET, SOCK_STREAM, 0); 18127185Sminshall if (s < 0) { 18227185Sminshall perror("telnetd: socket");; 18327185Sminshall exit(1); 18427185Sminshall } 18538904Sborman (void) setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); 18638904Sborman if (bind(s, (struct sockaddr *)&sin, sizeof sin) < 0) { 18727185Sminshall perror("bind"); 18827185Sminshall exit(1); 18927185Sminshall } 19027185Sminshall if (listen(s, 1) < 0) { 19127185Sminshall perror("listen"); 19227185Sminshall exit(1); 19327185Sminshall } 19427185Sminshall foo = sizeof sin; 19538904Sborman ns = accept(s, (struct sockaddr *)&sin, &foo); 19627185Sminshall if (ns < 0) { 19727185Sminshall perror("accept"); 19827185Sminshall exit(1); 19927185Sminshall } 20038904Sborman (void) dup2(ns, 0); 20138904Sborman (void) close(ns); 20238904Sborman (void) close(s); 20327185Sminshall } 20438904Sborman 20524855Seric openlog("telnetd", LOG_PID | LOG_ODELAY, LOG_DAEMON); 20616371Skarels fromlen = sizeof (from); 20738904Sborman if (getpeername(0, (struct sockaddr *)&from, &fromlen) < 0) { 20838904Sborman fprintf(stderr, "%s: ", progname); 20916371Skarels perror("getpeername"); 21016371Skarels _exit(1); 2118346Ssam } 21217156Ssam if (setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof (on)) < 0) { 21317187Sralph syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m"); 21410418Ssam } 21540242Sborman 21640242Sborman #ifdef IP_TOS 21740242Sborman if ((tp = gettosbyname("telnet", "tcp")) && 21840242Sborman (setsockopt(0, IPPROTO_IP, IP_TOS, &tp->t_tos, sizeof(int)) < 0)) 21940242Sborman syslog(LOG_WARNING, "setsockopt (IP_TOS): %m"); 22040242Sborman #endif /* IP_TOS */ 22138904Sborman net = 0; 22238904Sborman doit(&from); 22338904Sborman /* NOTREACHED */ 22438904Sborman } /* end of main */ 2256002Sroot 22640242Sborman void cleanup(); 22727649Sminshall 22827649Sminshall /* 22927983Sminshall * getterminaltype 23027649Sminshall * 23138904Sborman * Ask the other end to send along its terminal type and speed. 23227983Sminshall * Output is the variable terminaltype filled in. 23327649Sminshall */ 23438904Sborman static char ttytype_sbbuf[] = { IAC, SB, TELOPT_TTYPE, TELQUAL_SEND, IAC, SE }; 23527983Sminshall void 23627983Sminshall getterminaltype() 23727649Sminshall { 23838904Sborman void ttloop(); 23927649Sminshall 24038904Sborman settimer(baseline); 24139503Sborman send_do(TELOPT_TTYPE, 1); 24239503Sborman send_do(TELOPT_TSPEED, 1); 24338904Sborman while ((hiswants[TELOPT_TTYPE] != hisopts[TELOPT_TTYPE]) || 24438904Sborman (hiswants[TELOPT_TSPEED] != hisopts[TELOPT_TSPEED])) { 24527983Sminshall ttloop(); 24627649Sminshall } 24738904Sborman if (hisopts[TELOPT_TSPEED] == OPT_YES) { 24838904Sborman static char sbbuf[] = { IAC, SB, TELOPT_TSPEED, TELQUAL_SEND, IAC, SE }; 24927983Sminshall 25027983Sminshall bcopy(sbbuf, nfrontp, sizeof sbbuf); 25127983Sminshall nfrontp += sizeof sbbuf; 25238904Sborman } 25338904Sborman if (hisopts[TELOPT_TTYPE] == OPT_YES) { 25438904Sborman 25538904Sborman bcopy(ttytype_sbbuf, nfrontp, sizeof ttytype_sbbuf); 25638904Sborman nfrontp += sizeof ttytype_sbbuf; 25738904Sborman } 25838904Sborman if (hisopts[TELOPT_TSPEED] == OPT_YES) { 25938904Sborman while (sequenceIs(tspeedsubopt, baseline)) 26027983Sminshall ttloop(); 26138904Sborman } 26238904Sborman if (hisopts[TELOPT_TTYPE] == OPT_YES) { 26338904Sborman char first[256], last[256]; 26438904Sborman 26538904Sborman while (sequenceIs(ttypesubopt, baseline)) 26638904Sborman ttloop(); 26738904Sborman 26838904Sborman if (!terminaltypeok(&terminaltype[5])) { 26938904Sborman (void) strncpy(first, terminaltype, sizeof(first)); 27038904Sborman for(;;) { 27138904Sborman /* 27238904Sborman * Save the unknown name, and request the next name. 27338904Sborman */ 27438904Sborman (void) strncpy(last, terminaltype, sizeof(last)); 27538904Sborman _gettermname(); 27638904Sborman if (terminaltypeok(&terminaltype[5])) 27738904Sborman break; 27838904Sborman if (strncmp(last, terminaltype, sizeof(last)) == 0) { 27938904Sborman /* 28038904Sborman * We've hit the end. If this is the same as 28138904Sborman * the first name, just go with it. 28238904Sborman */ 28338904Sborman if (strncmp(first, terminaltype, sizeof(first) == 0)) 28438904Sborman break; 28538904Sborman /* 28638904Sborman * Get the terminal name one more type, so that 28738904Sborman * RFC1091 compliant telnets will cycle back to 28838904Sborman * the start of the list. 28938904Sborman */ 29038904Sborman _gettermname(); 29138904Sborman if (strncmp(first, terminaltype, sizeof(first) != 0)) 29238904Sborman (void) strncpy(terminaltype, first, sizeof(first)); 29338904Sborman break; 29438904Sborman } 29538904Sborman } 29627983Sminshall } 29727983Sminshall } 29838904Sborman } /* end of getterminaltype */ 29938904Sborman 30038904Sborman _gettermname() 30138904Sborman { 30238904Sborman settimer(baseline); 30338904Sborman bcopy(ttytype_sbbuf, nfrontp, sizeof ttytype_sbbuf); 30438904Sborman nfrontp += sizeof ttytype_sbbuf; 30538904Sborman while (sequenceIs(ttypesubopt, baseline)) 30638904Sborman ttloop(); 30727649Sminshall } 30827649Sminshall 30938904Sborman terminaltypeok(s) 31038904Sborman char *s; 31138904Sborman { 31238904Sborman char buf[1024]; 31338904Sborman 31438904Sborman if (terminaltype == NULL) 31538904Sborman return(1); 31638904Sborman 31738904Sborman /* 31838904Sborman * tgetent() will return 1 if the type is known, and 31938904Sborman * 0 if it is not known. If it returns -1, it couldn't 32038904Sborman * open the database. But if we can't open the database, 32138904Sborman * it won't help to say we failed, because we won't be 32238904Sborman * able to verify anything else. So, we treat -1 like 1. 32338904Sborman */ 32438904Sborman if (tgetent(buf, s) == 0) 32538904Sborman return(0); 32638904Sborman return(1); 32738904Sborman } 32838904Sborman 3296002Sroot /* 3306002Sroot * Get a pty, scan input lines. 3316002Sroot */ 33238904Sborman doit(who) 33312683Ssam struct sockaddr_in *who; 3346002Sroot { 33520188Skarels char *host, *inet_ntoa(); 33638904Sborman int t; 33712683Ssam struct hostent *hp; 3386002Sroot 33938904Sborman /* 34038904Sborman * Find an available pty to use. 34138904Sborman */ 34238904Sborman pty = getpty(); 34338904Sborman if (pty < 0) 34438904Sborman fatal(net, "All network ports in use"); 34520188Skarels 34638904Sborman t = getptyslave(); 34738904Sborman 34838904Sborman /* get name of connected client */ 34938904Sborman hp = gethostbyaddr((char *)&who->sin_addr, sizeof (struct in_addr), 35012683Ssam who->sin_family); 35112683Ssam if (hp) 35212683Ssam host = hp->h_name; 35312683Ssam else 35417444Sralph host = inet_ntoa(who->sin_addr); 35527983Sminshall 35627983Sminshall /* 35738904Sborman * get terminal type. 35827983Sminshall */ 35927983Sminshall getterminaltype(); 36038904Sborman if (terminaltype == NULL) 36138904Sborman terminaltype = "TERM=network"; 36227983Sminshall 36327649Sminshall /* 36438904Sborman * Start up the login process on the slave side of the terminal 36527649Sminshall */ 36638904Sborman startslave(t, host); 36738904Sborman 36838904Sborman telnet(net, pty); /* begin server processing */ 3699244Ssam /*NOTREACHED*/ 37038904Sborman } /* end of doit */ 3719244Ssam 37238904Sborman #ifndef MAXHOSTNAMELEN 37338904Sborman #define MAXHOSTNAMELEN 64 37438904Sborman #endif MAXHOSTNAMELEN 3756002Sroot /* 3766002Sroot * Main loop. Select from pty and network, and 3776002Sroot * hand data to telnet receiver finite state machine. 3786002Sroot */ 3796002Sroot telnet(f, p) 38038904Sborman int f, p; 3816002Sroot { 3826002Sroot int on = 1; 38327898Skarels char hostname[MAXHOSTNAMELEN]; 38440242Sborman #if defined(CRAY2) && defined(UNICOS5) 38538904Sborman int termstat(); 38638904Sborman int interrupt(), sendbrk(); 38738904Sborman #endif 38833271Sminshall #define TABBUFSIZ 512 38933271Sminshall char defent[TABBUFSIZ]; 39033271Sminshall char defstrs[TABBUFSIZ]; 39133271Sminshall #undef TABBUFSIZ 39233271Sminshall char *HE; 39333271Sminshall char *HN; 39433271Sminshall char *IM; 39538904Sborman void netflush(); 39638904Sborman 39732400Sminshall /* 39838904Sborman * Initialize the slc mapping table. 39932400Sminshall */ 40038904Sborman get_slc_defaults(); 4016002Sroot 4028379Ssam /* 40338904Sborman * Do some tests where it is desireable to wait for a response. 40438904Sborman * Rather than doing them slowly, one at a time, do them all 40538904Sborman * at once. 4068379Ssam */ 40738904Sborman if (!myopts[TELOPT_SGA]) 40839503Sborman send_will(TELOPT_SGA, 1); 40912713Ssam /* 41027649Sminshall * Is the client side a 4.2 (NOT 4.3) system? We need to know this 41127649Sminshall * because 4.2 clients are unable to deal with TCP urgent data. 41227649Sminshall * 41327649Sminshall * To find out, we send out a "DO ECHO". If the remote system 41427649Sminshall * answers "WILL ECHO" it is probably a 4.2 client, and we note 41527649Sminshall * that fact ("WILL ECHO" ==> that the client will echo what 41627649Sminshall * WE, the server, sends it; it does NOT mean that the client will 41727649Sminshall * echo the terminal input). 41827649Sminshall */ 41939503Sborman send_do(TELOPT_ECHO, 1); 42027649Sminshall 42138904Sborman #ifdef LINEMODE 42238904Sborman if (hisopts[TELOPT_LINEMODE] == OPT_NO) { 42338904Sborman /* Query the peer for linemode support by trying to negotiate 42438904Sborman * the linemode option. 42538904Sborman */ 42638904Sborman linemode = 1; 42738904Sborman editmode = 0; 42839503Sborman send_do(TELOPT_LINEMODE, 1); /* send do linemode */ 42938904Sborman } 43038904Sborman #endif /* LINEMODE */ 43138904Sborman 43227649Sminshall /* 43338904Sborman * Send along a couple of other options that we wish to negotiate. 43438904Sborman */ 43539503Sborman send_do(TELOPT_NAWS, 1); 43639503Sborman send_will(TELOPT_STATUS, 1); 43738904Sborman flowmode = 1; /* default flow control state */ 43839503Sborman send_do(TELOPT_LFLOW, 1); 43938904Sborman 44038904Sborman /* 44138904Sborman * Spin, waiting for a response from the DO ECHO. However, 44238904Sborman * some REALLY DUMB telnets out there might not respond 44338904Sborman * to the DO ECHO. So, we spin looking for NAWS, (most dumb 44438904Sborman * telnets so far seem to respond with WONT for a DO that 44538904Sborman * they don't understand...) because by the time we get the 44638904Sborman * response, it will already have processed the DO ECHO. 44738904Sborman * Kludge upon kludge. 44838904Sborman */ 44938904Sborman while (hiswants[TELOPT_NAWS] != hisopts[TELOPT_NAWS]) 45038904Sborman ttloop(); 45138904Sborman 45238904Sborman /* 45338995Sborman * On the off chance that the telnet client is broken and does not 45438995Sborman * respond to the DO ECHO we sent, (after all, we did send the 45538995Sborman * DO NAWS negotiation after the DO ECHO, and we won't get here 45638995Sborman * until a response to the DO NAWS comes back) simulate the 45738995Sborman * receipt of a will echo. This will also send a WONT ECHO 45838995Sborman * to the client, since we assume that the client failed to 45938995Sborman * respond because it believes that it is already in DO ECHO 46038995Sborman * mode, which we do not want. 46138995Sborman */ 46240242Sborman if (hiswants[TELOPT_ECHO] == OPT_YES) { 46339503Sborman willoption(TELOPT_ECHO); 46440242Sborman } 46538995Sborman 46638995Sborman /* 46738995Sborman * Finally, to clean things up, we turn on our echo. This 46838995Sborman * will break stupid 4.2 telnets out of local terminal echo. 46938995Sborman */ 47038995Sborman 47138995Sborman if (!myopts[TELOPT_ECHO]) 47239503Sborman send_will(TELOPT_ECHO, 1); 47338995Sborman 47438995Sborman /* 47538904Sborman * Turn on packet mode, and default to line at at time mode. 47638904Sborman */ 47738904Sborman (void) ioctl(p, TIOCPKT, (char *)&on); 47838904Sborman #ifdef LINEMODE 47938904Sborman tty_setlinemode(1); 48038904Sborman 48138904Sborman # ifdef KLUDGELINEMODE 48238904Sborman /* 48338904Sborman * Continuing line mode support. If client does not support 48438904Sborman * real linemode, attempt to negotiate kludge linemode by sending 48538904Sborman * the do timing mark sequence. 48638904Sborman */ 48738904Sborman if (lmodetype < REAL_LINEMODE) 48839503Sborman send_do(TELOPT_TM, 1); 48938904Sborman # endif /* KLUDGELINEMODE */ 49038904Sborman #endif /* LINEMODE */ 49138904Sborman 49238904Sborman /* 49338904Sborman * Call telrcv() once to pick up anything received during 49438904Sborman * terminal type negotiation, 4.2/4.3 determination, and 49538904Sborman * linemode negotiation. 49638904Sborman */ 49738904Sborman telrcv(); 49838904Sborman 49938904Sborman (void) ioctl(f, FIONBIO, (char *)&on); 50038904Sborman (void) ioctl(p, FIONBIO, (char *)&on); 50140242Sborman #if defined(CRAY2) && defined(UNICOS5) 50238904Sborman init_termdriver(f, p, interrupt, sendbrk); 50338904Sborman #endif 50438904Sborman 50538904Sborman #if defined(SO_OOBINLINE) 50638904Sborman (void) setsockopt(net, SOL_SOCKET, SO_OOBINLINE, &on, sizeof on); 50738904Sborman #endif /* defined(SO_OOBINLINE) */ 50838904Sborman 50938904Sborman #ifdef SIGTSTP 51038904Sborman (void) signal(SIGTSTP, SIG_IGN); 51138904Sborman #endif 51238904Sborman #ifdef SIGTTOU 51338904Sborman /* 51438904Sborman * Ignoring SIGTTOU keeps the kernel from blocking us 51538904Sborman * in ttioct() in /sys/tty.c. 51638904Sborman */ 51738904Sborman (void) signal(SIGTTOU, SIG_IGN); 51838904Sborman #endif 51938904Sborman 52038904Sborman (void) signal(SIGCHLD, cleanup); 52138904Sborman 52240242Sborman #if defined(CRAY2) && defined(UNICOS5) 52338904Sborman /* 52438904Sborman * Cray-2 will send a signal when pty modes are changed by slave 52538904Sborman * side. Set up signal handler now. 52638904Sborman */ 52738904Sborman if ((int)signal(SIGUSR1, termstat) < 0) 52838904Sborman perror("signal"); 52938904Sborman else if (ioctl(p, TCSIGME, (char *)SIGUSR1) < 0) 53038904Sborman perror("ioctl:TCSIGME"); 53138904Sborman /* 53238904Sborman * Make processing loop check terminal characteristics early on. 53338904Sborman */ 53438904Sborman termstat(); 53538904Sborman #endif 53638904Sborman 53738904Sborman (void) setpgrp(0, 0); 53840242Sborman #ifdef TCSETCTTY 53940242Sborman ioctl(p, TCSETCTTY, 0); 54040242Sborman #endif 54138904Sborman 54238904Sborman /* 54312713Ssam * Show banner that getty never gave. 54427797Sminshall * 54533271Sminshall * We put the banner in the pty input buffer. This way, it 54633271Sminshall * gets carriage return null processing, etc., just like all 54733271Sminshall * other pty --> client data. 54812713Ssam */ 54927797Sminshall 55038904Sborman (void) gethostname(hostname, sizeof (hostname)); 55138904Sborman 55233271Sminshall if (getent(defent, "default") == 1) { 55333271Sminshall char *getstr(); 55438904Sborman char *cp=defstrs; 55527649Sminshall 55638904Sborman HE = getstr("he", &cp); 55738904Sborman HN = getstr("hn", &cp); 55838904Sborman IM = getstr("im", &cp); 55933271Sminshall if (HN && *HN) 56038904Sborman (void) strcpy(hostname, HN); 56138904Sborman if (IM == 0) 56238904Sborman IM = ""; 56333271Sminshall } else { 56438904Sborman #ifdef CRAY 56538904Sborman if (hostinfo == 0) 56638904Sborman IM = 0; 56738904Sborman else 56838904Sborman #endif 56938904Sborman IM = DEFAULT_IM; 57038904Sborman HE = 0; 57133271Sminshall } 57238904Sborman edithost(HE, hostname); 57338904Sborman if (IM && *IM) 57438904Sborman putf(IM, ptyibuf2); 57527797Sminshall 57638904Sborman if (pcc) 57738904Sborman (void) strncat(ptyibuf2, ptyip, pcc+1); 57838904Sborman ptyip = ptyibuf2; 57938904Sborman pcc = strlen(ptyip); 58040242Sborman #ifdef LINEMODE 58140242Sborman /* 58240242Sborman * Last check to make sure all our states are correct. 58340242Sborman */ 58440242Sborman init_termbuf(); 58540242Sborman localstat(); 58640242Sborman #endif /* LINEMODE */ 58733271Sminshall 5886002Sroot for (;;) { 58927185Sminshall fd_set ibits, obits, xbits; 5906002Sroot register int c; 5916002Sroot 59227185Sminshall if (ncc < 0 && pcc < 0) 59327185Sminshall break; 59427185Sminshall 59540242Sborman #if defined(CRAY2) && defined(UNICOS5) 59638904Sborman if (needtermstat) 59738904Sborman _termstat(); 59840242Sborman #endif /* defined(CRAY2) && defined(UNICOS5) */ 59927185Sminshall FD_ZERO(&ibits); 60027185Sminshall FD_ZERO(&obits); 60127185Sminshall FD_ZERO(&xbits); 6026002Sroot /* 6036002Sroot * Never look for input if there's still 6046002Sroot * stuff in the corresponding output buffer 6056002Sroot */ 60627185Sminshall if (nfrontp - nbackp || pcc > 0) { 60727185Sminshall FD_SET(f, &obits); 60827185Sminshall } else { 60927185Sminshall FD_SET(p, &ibits); 61027185Sminshall } 61127185Sminshall if (pfrontp - pbackp || ncc > 0) { 61227185Sminshall FD_SET(p, &obits); 61327185Sminshall } else { 61427185Sminshall FD_SET(f, &ibits); 61527185Sminshall } 61627185Sminshall if (!SYNCHing) { 61727185Sminshall FD_SET(f, &xbits); 61827185Sminshall } 61927185Sminshall if ((c = select(16, &ibits, &obits, &xbits, 62027185Sminshall (struct timeval *)0)) < 1) { 62127185Sminshall if (c == -1) { 62227185Sminshall if (errno == EINTR) { 62327185Sminshall continue; 62427185Sminshall } 62527185Sminshall } 6266002Sroot sleep(5); 6276002Sroot continue; 6286002Sroot } 6296002Sroot 6306002Sroot /* 63127185Sminshall * Any urgent data? 63227185Sminshall */ 63327185Sminshall if (FD_ISSET(net, &xbits)) { 63427185Sminshall SYNCHing = 1; 63527185Sminshall } 63627185Sminshall 63727185Sminshall /* 6386002Sroot * Something to read from the network... 6396002Sroot */ 64027185Sminshall if (FD_ISSET(net, &ibits)) { 64127649Sminshall #if !defined(SO_OOBINLINE) 64227185Sminshall /* 64327898Skarels * In 4.2 (and 4.3 beta) systems, the 64427185Sminshall * OOB indication and data handling in the kernel 64527185Sminshall * is such that if two separate TCP Urgent requests 64627185Sminshall * come in, one byte of TCP data will be overlaid. 64727185Sminshall * This is fatal for Telnet, but we try to live 64827185Sminshall * with it. 64927185Sminshall * 65027185Sminshall * In addition, in 4.2 (and...), a special protocol 65127185Sminshall * is needed to pick up the TCP Urgent data in 65227185Sminshall * the correct sequence. 65327185Sminshall * 65427185Sminshall * What we do is: if we think we are in urgent 65527185Sminshall * mode, we look to see if we are "at the mark". 65627185Sminshall * If we are, we do an OOB receive. If we run 65727185Sminshall * this twice, we will do the OOB receive twice, 65827185Sminshall * but the second will fail, since the second 65927185Sminshall * time we were "at the mark", but there wasn't 66027185Sminshall * any data there (the kernel doesn't reset 66127185Sminshall * "at the mark" until we do a normal read). 66227185Sminshall * Once we've read the OOB data, we go ahead 66327185Sminshall * and do normal reads. 66427185Sminshall * 66527185Sminshall * There is also another problem, which is that 66627185Sminshall * since the OOB byte we read doesn't put us 66727185Sminshall * out of OOB state, and since that byte is most 66827185Sminshall * likely the TELNET DM (data mark), we would 66927185Sminshall * stay in the TELNET SYNCH (SYNCHing) state. 67027185Sminshall * So, clocks to the rescue. If we've "just" 67127185Sminshall * received a DM, then we test for the 67227185Sminshall * presence of OOB data when the receive OOB 67327185Sminshall * fails (and AFTER we did the normal mode read 67427185Sminshall * to clear "at the mark"). 67527185Sminshall */ 67627185Sminshall if (SYNCHing) { 67727185Sminshall int atmark; 67827185Sminshall 67938904Sborman (void) ioctl(net, SIOCATMARK, (char *)&atmark); 68027185Sminshall if (atmark) { 68127185Sminshall ncc = recv(net, netibuf, sizeof (netibuf), MSG_OOB); 68227185Sminshall if ((ncc == -1) && (errno == EINVAL)) { 68327185Sminshall ncc = read(net, netibuf, sizeof (netibuf)); 68427983Sminshall if (sequenceIs(didnetreceive, gotDM)) { 68527185Sminshall SYNCHing = stilloob(net); 68627185Sminshall } 68727185Sminshall } 68827185Sminshall } else { 68927185Sminshall ncc = read(net, netibuf, sizeof (netibuf)); 6906002Sroot } 69127185Sminshall } else { 69227185Sminshall ncc = read(net, netibuf, sizeof (netibuf)); 69327185Sminshall } 69427185Sminshall settimer(didnetreceive); 69527649Sminshall #else /* !defined(SO_OOBINLINE)) */ 69627185Sminshall ncc = read(net, netibuf, sizeof (netibuf)); 69727649Sminshall #endif /* !defined(SO_OOBINLINE)) */ 69827185Sminshall if (ncc < 0 && errno == EWOULDBLOCK) 69927185Sminshall ncc = 0; 70027185Sminshall else { 70127185Sminshall if (ncc <= 0) { 70227185Sminshall break; 70327185Sminshall } 70427185Sminshall netip = netibuf; 70527185Sminshall } 7066002Sroot } 7076002Sroot 7086002Sroot /* 7096002Sroot * Something to read from the pty... 7106002Sroot */ 71138904Sborman if (FD_ISSET(p, &ibits)) { 7126002Sroot pcc = read(p, ptyibuf, BUFSIZ); 7136002Sroot if (pcc < 0 && errno == EWOULDBLOCK) 7146002Sroot pcc = 0; 7156002Sroot else { 7166002Sroot if (pcc <= 0) 7176002Sroot break; 71840242Sborman #if !defined(CRAY2) || !defined(UNICOS5) 71938904Sborman #ifdef LINEMODE 72038904Sborman /* 72138904Sborman * If ioctl from pty, pass it through net 72238904Sborman */ 72338904Sborman if (ptyibuf[0] & TIOCPKT_IOCTL) { 72438904Sborman copy_termbuf(ptyibuf+1, pcc-1); 72538904Sborman localstat(); 72638904Sborman pcc = 1; 72738904Sborman } 72838904Sborman #endif LINEMODE 72937210Sminshall if (ptyibuf[0] & TIOCPKT_FLUSHWRITE) { 73038904Sborman netclear(); /* clear buffer back */ 73140242Sborman #ifdef notdef 73240242Sborman /* 73340242Sborman * We really should have this in, but 73440242Sborman * there are client telnets on some 73540242Sborman * operating systems get screwed up 73640242Sborman * royally if we send them urgent 73740242Sborman * mode data. So, for now, we'll not 73840242Sborman * do this... 73940242Sborman */ 74037210Sminshall *nfrontp++ = IAC; 74137210Sminshall *nfrontp++ = DM; 74237210Sminshall neturg = nfrontp-1; /* off by one XXX */ 74340242Sborman #endif 74437210Sminshall } 74537210Sminshall if (hisopts[TELOPT_LFLOW] && 74637210Sminshall (ptyibuf[0] & 74738904Sborman (TIOCPKT_NOSTOP|TIOCPKT_DOSTOP))) { 74838904Sborman (void) sprintf(nfrontp, "%c%c%c%c%c%c", 74937210Sminshall IAC, SB, TELOPT_LFLOW, 75037210Sminshall ptyibuf[0] & TIOCPKT_DOSTOP ? 1 : 0, 75137210Sminshall IAC, SE); 75237210Sminshall nfrontp += 6; 75337210Sminshall } 75433267Sminshall pcc--; 75533267Sminshall ptyip = ptyibuf+1; 75640242Sborman #else /* defined(CRAY2) && defined(UNICOS5) */ 75738904Sborman if (!uselinemode) { 75839531Sborman unpcc = pcc; 75939531Sborman unptyip = ptyibuf; 76039531Sborman pcc = term_output(&unptyip, ptyibuf2, 76139531Sborman &unpcc, BUFSIZ); 76238904Sborman ptyip = ptyibuf2; 76338904Sborman } else 76438904Sborman ptyip = ptyibuf; 76540242Sborman #endif /* defined(CRAY2) && defined(UNICOS5) */ 76638904Sborman } 7676002Sroot } 7686002Sroot 7696002Sroot while (pcc > 0) { 7706002Sroot if ((&netobuf[BUFSIZ] - nfrontp) < 2) 7716002Sroot break; 7726002Sroot c = *ptyip++ & 0377, pcc--; 7736002Sroot if (c == IAC) 7746002Sroot *nfrontp++ = c; 77540242Sborman #if defined(CRAY2) && defined(UNICOS5) 77638904Sborman else if (c == '\n' && 77738904Sborman myopts[TELOPT_BINARY] == OPT_NO && newmap) 77838904Sborman *nfrontp++ = '\r'; 77940242Sborman #endif /* defined(CRAY2) && defined(UNICOS5) */ 7806002Sroot *nfrontp++ = c; 78131940Sbostic if ((c == '\r') && (myopts[TELOPT_BINARY] == OPT_NO)) { 78227020Sminshall if (pcc > 0 && ((*ptyip & 0377) == '\n')) { 78327020Sminshall *nfrontp++ = *ptyip++ & 0377; 78427020Sminshall pcc--; 78527020Sminshall } else 78627020Sminshall *nfrontp++ = '\0'; 78727020Sminshall } 7886002Sroot } 78940242Sborman #if defined(CRAY2) && defined(UNICOS5) 79039531Sborman /* 79139531Sborman * If chars were left over from the terminal driver, 79239531Sborman * note their existence. 79339531Sborman */ 79439531Sborman if (!uselinemode && unpcc) { 79539531Sborman pcc = unpcc; 79639531Sborman unpcc = 0; 79739531Sborman ptyip = unptyip; 79839531Sborman } 79940242Sborman #endif /* defined(CRAY2) && defined(UNICOS5) */ 80039531Sborman 80127185Sminshall if (FD_ISSET(f, &obits) && (nfrontp - nbackp) > 0) 8026002Sroot netflush(); 8036002Sroot if (ncc > 0) 8046002Sroot telrcv(); 80527185Sminshall if (FD_ISSET(p, &obits) && (pfrontp - pbackp) > 0) 8066002Sroot ptyflush(); 8076002Sroot } 8086002Sroot cleanup(); 80938904Sborman } /* end of telnet */ 8106002Sroot 81138904Sborman #ifndef TCSIG 81238904Sborman # ifdef TIOCSIG 81338904Sborman # define TCSIG TIOCSIG 81438904Sborman # endif 81538904Sborman #endif 8166002Sroot 81737212Sminshall /* 8186002Sroot * Send interrupt to process on other side of pty. 8196002Sroot * If it is in raw mode, just write NULL; 8206002Sroot * otherwise, write intr char. 8216002Sroot */ 8226002Sroot interrupt() 8236002Sroot { 82438904Sborman ptyflush(); /* half-hearted */ 8256002Sroot 82638904Sborman #ifdef TCSIG 82738904Sborman (void) ioctl(pty, TCSIG, (char *)SIGINT); 82838904Sborman #else /* TCSIG */ 82938904Sborman init_termbuf(); 83040242Sborman *pfrontp++ = slctab[SLC_IP].sptr ? 83140242Sborman (unsigned char)*slctab[SLC_IP].sptr : '\177'; 83238904Sborman #endif /* TCSIG */ 8336002Sroot } 8346002Sroot 83527229Sminshall /* 83627229Sminshall * Send quit to process on other side of pty. 83727229Sminshall * If it is in raw mode, just write NULL; 83827229Sminshall * otherwise, write quit char. 83927229Sminshall */ 84027229Sminshall sendbrk() 84127229Sminshall { 84227229Sminshall ptyflush(); /* half-hearted */ 84338904Sborman #ifdef TCSIG 84438904Sborman (void) ioctl(pty, TCSIG, (char *)SIGQUIT); 84538904Sborman #else /* TCSIG */ 84638904Sborman init_termbuf(); 84740242Sborman *pfrontp++ = slctab[SLC_ABORT].sptr ? 84840242Sborman (unsigned char)*slctab[SLC_ABORT].sptr : '\034'; 84938904Sborman #endif /* TCSIG */ 85027229Sminshall } 85127229Sminshall 85238904Sborman sendsusp() 8536002Sroot { 85438904Sborman #ifdef SIGTSTP 85538904Sborman ptyflush(); /* half-hearted */ 85638904Sborman # ifdef TCSIG 85738904Sborman (void) ioctl(pty, TCSIG, (char *)SIGTSTP); 85838904Sborman # else /* TCSIG */ 85940242Sborman *pfrontp++ = slctab[SLC_SUSP].sptr ? 86040242Sborman (unsigned char)*slctab[SLC_SUSP].sptr : '\032'; 86138904Sborman # endif /* TCSIG */ 86238904Sborman #endif /* SIGTSTP */ 8636002Sroot } 8646002Sroot 86538904Sborman doeof() 8666002Sroot { 86740242Sborman #if defined(USE_TERMIO) && defined(SYSV_TERMIO) 86840242Sborman extern char oldeofc; 86940242Sborman #endif 87038904Sborman init_termbuf(); 8716002Sroot 87240242Sborman #if defined(USE_TERMIO) && defined(SYSV_TERMIO) 87340242Sborman if (!tty_isediting()) { 87440242Sborman *pfrontp++ = oldeofc; 87540242Sborman return; 87640242Sborman } 87740242Sborman #endif 87840242Sborman *pfrontp++ = slctab[SLC_EOF].sptr ? 87940242Sborman (unsigned char)*slctab[SLC_EOF].sptr : '\004'; 8806002Sroot } 881