121182Sdist /* 238904Sborman * Copyright (c) 1989 Regents of the University of California. 333687Sbostic * All rights reserved. 433687Sbostic * 542673Sbostic * %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*46809Sdab static char sccsid[] = "@(#)telnetd.c 5.48 (Berkeley) 03/01/91"; 1633687Sbostic #endif /* not lint */ 1721182Sdist 1838904Sborman #include "telnetd.h" 1945234Sborman #include "pathnames.h" 2038904Sborman 21*46809Sdab #if defined(AUTHENTICATE) 22*46809Sdab #include <libtelnet/auth.h> 23*46809Sdab int auth_level = 0; 24*46809Sdab #endif 25*46809Sdab #if defined(SecurID) 26*46809Sdab int require_SecurID = 0; 27*46809Sdab #endif 28*46809Sdab 296002Sroot /* 3038904Sborman * I/O data buffers, 3138904Sborman * pointers, and counters. 326002Sroot */ 3338904Sborman char ptyibuf[BUFSIZ], *ptyip = ptyibuf; 3438904Sborman char ptyibuf2[BUFSIZ]; 359218Ssam 3638904Sborman int hostinfo = 1; /* do we print login banner? */ 379218Ssam 3838904Sborman #ifdef CRAY 3938904Sborman extern int newmap; /* nonzero if \n maps to ^M^J */ 4040242Sborman int lowpty = 0, highpty; /* low, high pty numbers */ 4138904Sborman #endif /* CRAY */ 4212216Ssam 4338904Sborman int debug = 0; 44*46809Sdab int keepalive = 1; 4538904Sborman char *progname; 469218Ssam 47*46809Sdab extern void usage P((void)); 4844363Sborman 4938904Sborman main(argc, argv) 5038904Sborman char *argv[]; 5138904Sborman { 5238904Sborman struct sockaddr_in from; 5338904Sborman int on = 1, fromlen; 54*46809Sdab register int ch; 55*46809Sdab extern char *optarg; 56*46809Sdab extern int optind; 57*46809Sdab #if defined(IPPROTO_IP) && defined(IP_TOS) 58*46809Sdab int tos = -1; 59*46809Sdab #endif 606002Sroot 6138904Sborman pfrontp = pbackp = ptyobuf; 6238904Sborman netip = netibuf; 6338904Sborman nfrontp = nbackp = netobuf; 64*46809Sdab #if defined(ENCRYPT) 65*46809Sdab nclearto = 0; 66*46809Sdab #endif 676002Sroot 6838904Sborman progname = *argv; 6940242Sborman 7040242Sborman #ifdef CRAY 7140242Sborman /* 7240242Sborman * Get number of pty's before trying to process options, 7340242Sborman * which may include changing pty range. 7440242Sborman */ 7540242Sborman highpty = getnpty(); 7640242Sborman #endif /* CRAY */ 7740242Sborman 78*46809Sdab while ((ch = getopt(argc, argv, "d:a:e:lhnr:I:D:B:sS:a:X:")) != EOF) { 79*46809Sdab switch(ch) { 8027649Sminshall 81*46809Sdab #ifdef AUTHENTICATE 82*46809Sdab case 'a': 83*46809Sdab /* 84*46809Sdab * Check for required authentication level 85*46809Sdab */ 86*46809Sdab if (strcmp(optarg, "debug") == 0) { 87*46809Sdab extern int auth_debug_mode; 88*46809Sdab auth_debug_mode = 1; 89*46809Sdab } else if (strcasecmp(optarg, "none") == 0) { 90*46809Sdab auth_level = 0; 91*46809Sdab } else if (strcasecmp(optarg, "other") == 0) { 92*46809Sdab auth_level = AUTH_OTHER; 93*46809Sdab } else if (strcasecmp(optarg, "user") == 0) { 94*46809Sdab auth_level = AUTH_USER; 95*46809Sdab } else if (strcasecmp(optarg, "valid") == 0) { 96*46809Sdab auth_level = AUTH_VALID; 97*46809Sdab } else if (strcasecmp(optarg, "off") == 0) { 98*46809Sdab /* 99*46809Sdab * This hack turns off authentication 100*46809Sdab */ 101*46809Sdab auth_level = -1; 102*46809Sdab } else { 103*46809Sdab fprintf(stderr, 104*46809Sdab "telnetd: unknown authorization level for -a\n"); 105*46809Sdab } 106*46809Sdab break; 107*46809Sdab #endif /* AUTHENTICATE */ 10827649Sminshall 109*46809Sdab #ifdef BFTPDAEMON 110*46809Sdab case 'B': 111*46809Sdab bftpd++; 112*46809Sdab break; 113*46809Sdab #endif /* BFTPDAEMON */ 114*46809Sdab 115*46809Sdab case 'd': 116*46809Sdab if (strcmp(optarg, "ebug") == 0) { 117*46809Sdab debug++; 118*46809Sdab break; 119*46809Sdab } 120*46809Sdab usage(); 121*46809Sdab /* NOTREACHED */ 122*46809Sdab break; 123*46809Sdab 124*46809Sdab #ifdef DIAGNOSTICS 125*46809Sdab case 'D': 126*46809Sdab /* 127*46809Sdab * Check for desired diagnostics capabilities. 128*46809Sdab */ 129*46809Sdab if (!strcmp(optarg, "report")) { 130*46809Sdab diagnostic |= TD_REPORT|TD_OPTIONS; 131*46809Sdab } else if (!strcmp(optarg, "exercise")) { 132*46809Sdab diagnostic |= TD_EXERCISE; 133*46809Sdab } else if (!strcmp(optarg, "netdata")) { 134*46809Sdab diagnostic |= TD_NETDATA; 135*46809Sdab } else if (!strcmp(optarg, "ptydata")) { 136*46809Sdab diagnostic |= TD_PTYDATA; 137*46809Sdab } else if (!strcmp(optarg, "options")) { 138*46809Sdab diagnostic |= TD_OPTIONS; 139*46809Sdab } else { 140*46809Sdab usage(); 141*46809Sdab /* NOT REACHED */ 142*46809Sdab } 143*46809Sdab break; 144*46809Sdab #endif /* DIAGNOSTICS */ 145*46809Sdab 146*46809Sdab #ifdef AUTHENTICATE 147*46809Sdab case 'e': 148*46809Sdab if (strcmp(optarg, "debug") == 0) { 149*46809Sdab extern int encrypt_debug_mode; 150*46809Sdab encrypt_debug_mode = 1; 151*46809Sdab break; 152*46809Sdab } 153*46809Sdab usage(); 154*46809Sdab /* NOTREACHED */ 155*46809Sdab break; 156*46809Sdab #endif /* AUTHENTICATE */ 157*46809Sdab 158*46809Sdab case 'h': 159*46809Sdab hostinfo = 0; 160*46809Sdab break; 161*46809Sdab 162*46809Sdab #if defined(CRAY) && defined(NEWINIT) 163*46809Sdab case 'I': 164*46809Sdab { 165*46809Sdab extern char *gen_id; 166*46809Sdab gen_id = optarg; 167*46809Sdab break; 168*46809Sdab } 169*46809Sdab #endif /* defined(CRAY) && defined(NEWINIT) */ 170*46809Sdab 17138904Sborman #ifdef LINEMODE 172*46809Sdab case 'l': 173*46809Sdab alwayslinemode = 1; 174*46809Sdab break; 17538904Sborman #endif /* LINEMODE */ 17627649Sminshall 177*46809Sdab case 'n': 178*46809Sdab keepalive = 0; 179*46809Sdab break; 18027649Sminshall 18145234Sborman #ifdef CRAY 182*46809Sdab case 'r': 183*46809Sdab { 184*46809Sdab char *strchr(); 185*46809Sdab char *c; 18627649Sminshall 187*46809Sdab /* 188*46809Sdab * Allow the specification of alterations 189*46809Sdab * to the pty search range. It is legal to 190*46809Sdab * specify only one, and not change the 191*46809Sdab * other from its default. 192*46809Sdab */ 193*46809Sdab c = strchr(optarg, '-'); 194*46809Sdab if (c) { 195*46809Sdab *c++ = '\0'; 196*46809Sdab highpty = atoi(c); 19744363Sborman } 198*46809Sdab if (*optarg != '\0') 199*46809Sdab lowpty = atoi(optarg); 200*46809Sdab if ((lowpty > highpty) || (lowpty < 0) || 201*46809Sdab (highpty > 32767)) { 20244363Sborman usage(); 20344363Sborman /* NOT REACHED */ 20444363Sborman } 205*46809Sdab break; 206*46809Sdab } 20738904Sborman #endif /* CRAY */ 2086002Sroot 209*46809Sdab #ifdef SecurID 210*46809Sdab case 's': 211*46809Sdab /* SecurID required */ 212*46809Sdab require_SecurID = 1; 213*46809Sdab break; 214*46809Sdab #endif /* SecurID */ 215*46809Sdab case 'S': 216*46809Sdab #ifdef HAS_GETTOS 217*46809Sdab if ((tos = parsetos(optarg, "tcp")) < 0) 218*46809Sdab fprintf(stderr, "%s%s%s\n", 219*46809Sdab "telnetd: Bad TOS argument '", optarg, 220*46809Sdab "'; will try to use default TOS"); 221*46809Sdab #else 222*46809Sdab fprintf(stderr, "%s%s\n", "TOS option unavailable; ", 223*46809Sdab "-S flag not supported\n"); 224*46809Sdab #endif 225*46809Sdab break; 226*46809Sdab 227*46809Sdab #ifdef AUTHENTICATE 228*46809Sdab case 'X': 229*46809Sdab /* 230*46809Sdab * Check for invalid authentication types 231*46809Sdab */ 232*46809Sdab auth_disable_name(optarg); 233*46809Sdab break; 234*46809Sdab #endif /* AUTHENTICATE */ 235*46809Sdab 236*46809Sdab default: 237*46809Sdab fprintf(stderr, "telnetd: %s: unknown option\n", ch); 238*46809Sdab /* FALLTHROUGH */ 239*46809Sdab case '?': 24044363Sborman usage(); 241*46809Sdab /* NOTREACHED */ 24244363Sborman } 24344363Sborman } 24444363Sborman 245*46809Sdab argc -= optind; 246*46809Sdab argv += optind; 24744363Sborman 24838904Sborman if (debug) { 24927185Sminshall int s, ns, foo; 25027185Sminshall struct servent *sp; 25127185Sminshall static struct sockaddr_in sin = { AF_INET }; 25227185Sminshall 25344363Sborman if (argc > 1) { 25444363Sborman usage(); 25544363Sborman /* NOT REACHED */ 25644363Sborman } else if (argc == 1) { 25738904Sborman if (sp = getservbyname(*argv, "tcp")) { 25838904Sborman sin.sin_port = sp->s_port; 25938904Sborman } else { 26038904Sborman sin.sin_port = atoi(*argv); 26138904Sborman if ((int)sin.sin_port <= 0) { 26238904Sborman fprintf(stderr, "telnetd: %s: bad port #\n", *argv); 26344363Sborman usage(); 26444363Sborman /* NOT REACHED */ 26538904Sborman } 26638904Sborman sin.sin_port = htons((u_short)sin.sin_port); 26738904Sborman } 26837210Sminshall } else { 26937210Sminshall sp = getservbyname("telnet", "tcp"); 27037210Sminshall if (sp == 0) { 27144363Sborman fprintf(stderr, "telnetd: tcp/telnet: unknown service\n"); 27238904Sborman exit(1); 27337210Sminshall } 27437210Sminshall sin.sin_port = sp->s_port; 27527185Sminshall } 27627185Sminshall 27727185Sminshall s = socket(AF_INET, SOCK_STREAM, 0); 27827185Sminshall if (s < 0) { 27927185Sminshall perror("telnetd: socket");; 28027185Sminshall exit(1); 28127185Sminshall } 28238904Sborman (void) setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); 28338904Sborman if (bind(s, (struct sockaddr *)&sin, sizeof sin) < 0) { 28427185Sminshall perror("bind"); 28527185Sminshall exit(1); 28627185Sminshall } 28727185Sminshall if (listen(s, 1) < 0) { 28827185Sminshall perror("listen"); 28927185Sminshall exit(1); 29027185Sminshall } 29127185Sminshall foo = sizeof sin; 29238904Sborman ns = accept(s, (struct sockaddr *)&sin, &foo); 29327185Sminshall if (ns < 0) { 29427185Sminshall perror("accept"); 29527185Sminshall exit(1); 29627185Sminshall } 29738904Sborman (void) dup2(ns, 0); 29838904Sborman (void) close(ns); 29938904Sborman (void) close(s); 300*46809Sdab #ifdef convex 301*46809Sdab } else if (argc == 1) { 302*46809Sdab ; /* VOID*/ /* Just ignore the host/port name */ 303*46809Sdab #endif 30444363Sborman } else if (argc > 0) { 30544363Sborman usage(); 30644363Sborman /* NOT REACHED */ 30727185Sminshall } 30838904Sborman 30924855Seric openlog("telnetd", LOG_PID | LOG_ODELAY, LOG_DAEMON); 31016371Skarels fromlen = sizeof (from); 31138904Sborman if (getpeername(0, (struct sockaddr *)&from, &fromlen) < 0) { 31238904Sborman fprintf(stderr, "%s: ", progname); 31316371Skarels perror("getpeername"); 31416371Skarels _exit(1); 3158346Ssam } 316*46809Sdab if (keepalive && 317*46809Sdab setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof (on)) < 0) { 31817187Sralph syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m"); 31910418Ssam } 32040242Sborman 321*46809Sdab #if defined(IPPROTO_IP) && defined(IP_TOS) 322*46809Sdab { 323*46809Sdab # if defined(HAS_GETTOS) 324*46809Sdab struct tosent *tp; 325*46809Sdab if (tos < 0 && (tp = gettosbyname("telnet", "tcp"))) 326*46809Sdab tos = tp->t_tos; 327*46809Sdab # endif 328*46809Sdab if (tos < 0) 329*46809Sdab tos = 020; /* Low Delay bit */ 330*46809Sdab if (tos 331*46809Sdab && (setsockopt(0, IPPROTO_IP, IP_TOS, &tos, sizeof(tos)) < 0) 332*46809Sdab && (errno != ENOPROTOOPT) ) 333*46809Sdab syslog(LOG_WARNING, "setsockopt (IP_TOS): %m"); 334*46809Sdab } 335*46809Sdab #endif /* defined(IPPROTO_IP) && defined(IP_TOS) */ 33638904Sborman net = 0; 33738904Sborman doit(&from); 33838904Sborman /* NOTREACHED */ 33938904Sborman } /* end of main */ 3406002Sroot 341*46809Sdab void 34244363Sborman usage() 34344363Sborman { 344*46809Sdab fprintf(stderr, "Usage: telnetd"); 345*46809Sdab #ifdef AUTHENTICATE 346*46809Sdab fprintf(stderr, " [-a (debug|other|user|valid|off)]\n\t"); 347*46809Sdab #endif 348*46809Sdab #ifdef BFTPDAEMON 349*46809Sdab fprintf(stderr, " [-B]"); 350*46809Sdab #endif 351*46809Sdab fprintf(stderr, " [-debug]"); 352*46809Sdab #ifdef DIAGNOSTICS 353*46809Sdab fprintf(stderr, " [-D (options|report|exercise|netdata|ptydata)]\n\t"); 354*46809Sdab #endif 355*46809Sdab #ifdef AUTHENTICATE 356*46809Sdab fprintf(stderr, " [-edebug]"); 357*46809Sdab #endif 358*46809Sdab fprintf(stderr, " [-h]"); 359*46809Sdab #if defined(CRAY) && defined(NEWINIT) 36044363Sborman fprintf(stderr, " [-Iinitid]"); 361*46809Sdab #endif 36244363Sborman #ifdef LINEMODE 36344363Sborman fprintf(stderr, " [-l]"); 36444363Sborman #endif 365*46809Sdab fprintf(stderr, " [-n]"); 36644363Sborman #ifdef CRAY 36744363Sborman fprintf(stderr, " [-r[lowpty]-[highpty]]"); 36844363Sborman #endif 369*46809Sdab #ifdef SecurID 370*46809Sdab fprintf(stderr, " [-s]"); 371*46809Sdab #endif 372*46809Sdab #ifdef AUTHENTICATE 373*46809Sdab fprintf(stderr, " [-X auth-type]"); 374*46809Sdab #endif 37544363Sborman fprintf(stderr, " [port]\n"); 37644363Sborman exit(1); 37744363Sborman } 37844363Sborman 37927649Sminshall /* 38027983Sminshall * getterminaltype 38127649Sminshall * 38238904Sborman * Ask the other end to send along its terminal type and speed. 38327983Sminshall * Output is the variable terminaltype filled in. 38427649Sminshall */ 38538904Sborman static char ttytype_sbbuf[] = { IAC, SB, TELOPT_TTYPE, TELQUAL_SEND, IAC, SE }; 386*46809Sdab 387*46809Sdab int 388*46809Sdab getterminaltype(name) 389*46809Sdab char *name; 39027649Sminshall { 391*46809Sdab int retval = -1; 392*46809Sdab void _gettermname(); 39327649Sminshall 39438904Sborman settimer(baseline); 395*46809Sdab #if defined(AUTHENTICATE) 396*46809Sdab /* 397*46809Sdab * Handle the Authentication option before we do anything else. 398*46809Sdab */ 399*46809Sdab send_do(TELOPT_AUTHENTICATION, 1); 400*46809Sdab while (his_will_wont_is_changing(TELOPT_AUTHENTICATION)) 401*46809Sdab ttloop(); 402*46809Sdab if (his_state_is_will(TELOPT_AUTHENTICATION)) { 403*46809Sdab retval = auth_wait(name); 404*46809Sdab } 405*46809Sdab #endif 406*46809Sdab 407*46809Sdab #if defined(ENCRYPT) 408*46809Sdab send_will(TELOPT_ENCRYPT, 1); 409*46809Sdab #endif 41039503Sborman send_do(TELOPT_TTYPE, 1); 41139503Sborman send_do(TELOPT_TSPEED, 1); 41244363Sborman send_do(TELOPT_XDISPLOC, 1); 41344363Sborman send_do(TELOPT_ENVIRON, 1); 414*46809Sdab while ( 415*46809Sdab #if defined(ENCRYPT) 416*46809Sdab his_do_dont_is_changing(TELOPT_ENCRYPT) || 417*46809Sdab #endif 418*46809Sdab his_will_wont_is_changing(TELOPT_TTYPE) || 41944363Sborman his_will_wont_is_changing(TELOPT_TSPEED) || 42044363Sborman his_will_wont_is_changing(TELOPT_XDISPLOC) || 42144363Sborman his_will_wont_is_changing(TELOPT_ENVIRON)) { 42227983Sminshall ttloop(); 42327649Sminshall } 424*46809Sdab #if defined(ENCRYPT) 425*46809Sdab /* 426*46809Sdab * Wait for the negotiation of what type of encryption we can 427*46809Sdab * send with. If autoencrypt is not set, this will just return. 428*46809Sdab */ 429*46809Sdab if (his_state_is_will(TELOPT_ENCRYPT)) { 430*46809Sdab encrypt_wait(); 431*46809Sdab } 432*46809Sdab #endif 43344363Sborman if (his_state_is_will(TELOPT_TSPEED)) { 43438904Sborman static char sbbuf[] = { IAC, SB, TELOPT_TSPEED, TELQUAL_SEND, IAC, SE }; 43527983Sminshall 43627983Sminshall bcopy(sbbuf, nfrontp, sizeof sbbuf); 43727983Sminshall nfrontp += sizeof sbbuf; 43838904Sborman } 43944363Sborman if (his_state_is_will(TELOPT_XDISPLOC)) { 44044363Sborman static char sbbuf[] = { IAC, SB, TELOPT_XDISPLOC, TELQUAL_SEND, IAC, SE }; 44138904Sborman 44244363Sborman bcopy(sbbuf, nfrontp, sizeof sbbuf); 44344363Sborman nfrontp += sizeof sbbuf; 44444363Sborman } 44544363Sborman if (his_state_is_will(TELOPT_ENVIRON)) { 44644363Sborman static char sbbuf[] = { IAC, SB, TELOPT_ENVIRON, TELQUAL_SEND, IAC, SE }; 44744363Sborman 44844363Sborman bcopy(sbbuf, nfrontp, sizeof sbbuf); 44944363Sborman nfrontp += sizeof sbbuf; 45044363Sborman } 45144363Sborman if (his_state_is_will(TELOPT_TTYPE)) { 45244363Sborman 45338904Sborman bcopy(ttytype_sbbuf, nfrontp, sizeof ttytype_sbbuf); 45438904Sborman nfrontp += sizeof ttytype_sbbuf; 45538904Sborman } 45644363Sborman if (his_state_is_will(TELOPT_TSPEED)) { 45738904Sborman while (sequenceIs(tspeedsubopt, baseline)) 45827983Sminshall ttloop(); 45938904Sborman } 46044363Sborman if (his_state_is_will(TELOPT_XDISPLOC)) { 46144363Sborman while (sequenceIs(xdisplocsubopt, baseline)) 46244363Sborman ttloop(); 46344363Sborman } 46444363Sborman if (his_state_is_will(TELOPT_ENVIRON)) { 46544363Sborman while (sequenceIs(environsubopt, baseline)) 46644363Sborman ttloop(); 46744363Sborman } 46844363Sborman if (his_state_is_will(TELOPT_TTYPE)) { 46938904Sborman char first[256], last[256]; 47038904Sborman 47138904Sborman while (sequenceIs(ttypesubopt, baseline)) 47238904Sborman ttloop(); 47338904Sborman 47444363Sborman /* 47544363Sborman * If the other side has already disabled the option, then 47644363Sborman * we have to just go with what we (might) have already gotten. 47744363Sborman */ 47844363Sborman if (his_state_is_will(TELOPT_TTYPE) && !terminaltypeok(terminaltype)) { 47938904Sborman (void) strncpy(first, terminaltype, sizeof(first)); 48038904Sborman for(;;) { 48138904Sborman /* 48238904Sborman * Save the unknown name, and request the next name. 48338904Sborman */ 48438904Sborman (void) strncpy(last, terminaltype, sizeof(last)); 48538904Sborman _gettermname(); 48644363Sborman if (terminaltypeok(terminaltype)) 48738904Sborman break; 48844363Sborman if ((strncmp(last, terminaltype, sizeof(last)) == 0) || 48944363Sborman his_state_is_wont(TELOPT_TTYPE)) { 49038904Sborman /* 49138904Sborman * We've hit the end. If this is the same as 49238904Sborman * the first name, just go with it. 49338904Sborman */ 49445234Sborman if (strncmp(first, terminaltype, sizeof(first)) == 0) 49538904Sborman break; 49638904Sborman /* 49744363Sborman * Get the terminal name one more time, so that 49838904Sborman * RFC1091 compliant telnets will cycle back to 49938904Sborman * the start of the list. 50038904Sborman */ 50144363Sborman _gettermname(); 50245234Sborman if (strncmp(first, terminaltype, sizeof(first)) != 0) 50338904Sborman (void) strncpy(terminaltype, first, sizeof(first)); 50438904Sborman break; 50538904Sborman } 50638904Sborman } 50727983Sminshall } 50827983Sminshall } 509*46809Sdab return(retval); 51038904Sborman } /* end of getterminaltype */ 51138904Sborman 512*46809Sdab void 51338904Sborman _gettermname() 51438904Sborman { 51544363Sborman /* 51644363Sborman * If the client turned off the option, 51744363Sborman * we can't send another request, so we 51844363Sborman * just return. 51944363Sborman */ 52044363Sborman if (his_state_is_wont(TELOPT_TTYPE)) 52144363Sborman return; 52238904Sborman settimer(baseline); 52338904Sborman bcopy(ttytype_sbbuf, nfrontp, sizeof ttytype_sbbuf); 52438904Sborman nfrontp += sizeof ttytype_sbbuf; 52538904Sborman while (sequenceIs(ttypesubopt, baseline)) 52638904Sborman ttloop(); 52727649Sminshall } 52827649Sminshall 529*46809Sdab int 53038904Sborman terminaltypeok(s) 531*46809Sdab char *s; 53238904Sborman { 53338904Sborman char buf[1024]; 53438904Sborman 53538904Sborman if (terminaltype == NULL) 53638904Sborman return(1); 53738904Sborman 53838904Sborman /* 53938904Sborman * tgetent() will return 1 if the type is known, and 54038904Sborman * 0 if it is not known. If it returns -1, it couldn't 54138904Sborman * open the database. But if we can't open the database, 54238904Sborman * it won't help to say we failed, because we won't be 54338904Sborman * able to verify anything else. So, we treat -1 like 1. 54438904Sborman */ 54538904Sborman if (tgetent(buf, s) == 0) 54638904Sborman return(0); 54738904Sborman return(1); 54838904Sborman } 54938904Sborman 550*46809Sdab #ifndef MAXHOSTNAMELEN 551*46809Sdab #define MAXHOSTNAMELEN 64 552*46809Sdab #endif /* MAXHOSTNAMELEN */ 553*46809Sdab 554*46809Sdab char *hostname; 555*46809Sdab char host_name[MAXHOSTNAMELEN]; 556*46809Sdab char remote_host_name[MAXHOSTNAMELEN]; 557*46809Sdab 558*46809Sdab #ifndef convex 559*46809Sdab extern void telnet P((int, int)); 560*46809Sdab #else 561*46809Sdab extern void telnet P((int, int, char *)); 562*46809Sdab #endif 563*46809Sdab 5646002Sroot /* 5656002Sroot * Get a pty, scan input lines. 5666002Sroot */ 56738904Sborman doit(who) 56812683Ssam struct sockaddr_in *who; 5696002Sroot { 57020188Skarels char *host, *inet_ntoa(); 57138904Sborman int t; 57212683Ssam struct hostent *hp; 573*46809Sdab int level; 574*46809Sdab char user_name[256]; 5756002Sroot 57638904Sborman /* 57738904Sborman * Find an available pty to use. 57838904Sborman */ 57945234Sborman #ifndef convex 58038904Sborman pty = getpty(); 58138904Sborman if (pty < 0) 58238904Sborman fatal(net, "All network ports in use"); 58345234Sborman #else 58445234Sborman for (;;) { 58545234Sborman char *lp; 58645234Sborman extern char *line, *getpty(); 58720188Skarels 58845234Sborman if ((lp = getpty()) == NULL) 58945234Sborman fatal(net, "Out of ptys"); 59045234Sborman 59145234Sborman if ((pty = open(lp, 2)) >= 0) { 59245234Sborman strcpy(line,lp); 59345234Sborman line[5] = 't'; 59445234Sborman break; 59545234Sborman } 59645234Sborman } 59744545Smarc #endif 59838904Sborman 59938904Sborman /* get name of connected client */ 60038904Sborman hp = gethostbyaddr((char *)&who->sin_addr, sizeof (struct in_addr), 60112683Ssam who->sin_family); 60212683Ssam if (hp) 60312683Ssam host = hp->h_name; 60412683Ssam else 60517444Sralph host = inet_ntoa(who->sin_addr); 606*46809Sdab /* 607*46809Sdab * We must make a copy because Kerberos is probably going 608*46809Sdab * to also do a gethost* and overwrite the static data... 609*46809Sdab */ 610*46809Sdab strncpy(remote_host_name, host, sizeof(remote_host_name)-1); 611*46809Sdab remote_host_name[sizeof(remote_host_name)-1] = 0; 612*46809Sdab host = remote_host_name; 61327983Sminshall 614*46809Sdab (void) gethostname(host_name, sizeof (host_name)); 615*46809Sdab hostname = host_name; 616*46809Sdab 617*46809Sdab #if defined(AUTHENTICATE) || defined(ENCRYPT) 618*46809Sdab auth_encrypt_init(hostname, host, "TELNETD", 1); 619*46809Sdab #endif 620*46809Sdab 62144363Sborman init_env(); 62227983Sminshall /* 62338904Sborman * get terminal type. 62427983Sminshall */ 625*46809Sdab *user_name = 0; 626*46809Sdab level = getterminaltype(user_name); 62744363Sborman setenv("TERM", terminaltype ? terminaltype : "network", 1); 62827983Sminshall 62927649Sminshall /* 63038904Sborman * Start up the login process on the slave side of the terminal 63127649Sminshall */ 63245234Sborman #ifndef convex 633*46809Sdab startslave(host, level, user_name); 63438904Sborman 63538904Sborman telnet(net, pty); /* begin server processing */ 63645234Sborman #else 63745234Sborman telnet(net, pty, host); 63845234Sborman #endif 6399244Ssam /*NOTREACHED*/ 64038904Sborman } /* end of doit */ 6419244Ssam 642*46809Sdab #if defined(CRAY2) && defined(UNICOS5) && defined(UNICOS50) 643*46809Sdab int 644*46809Sdab Xterm_output(ibufp, obuf, icountp, ocount) 645*46809Sdab char **ibufp, *obuf; 646*46809Sdab int *icountp, ocount; 647*46809Sdab { 648*46809Sdab int ret; 649*46809Sdab ret = term_output(*ibufp, obuf, *icountp, ocount); 650*46809Sdab *ibufp += *icountp; 651*46809Sdab *icountp = 0; 652*46809Sdab return(ret); 653*46809Sdab } 654*46809Sdab #define term_output Xterm_output 655*46809Sdab #endif /* defined(CRAY2) && defined(UNICOS5) && defined(UNICOS50) */ 656*46809Sdab 6576002Sroot /* 6586002Sroot * Main loop. Select from pty and network, and 6596002Sroot * hand data to telnet receiver finite state machine. 6606002Sroot */ 661*46809Sdab void 66245234Sborman #ifndef convex 6636002Sroot telnet(f, p) 66445234Sborman #else 66545234Sborman telnet(f, p, host) 66645234Sborman #endif 667*46809Sdab int f, p; 66845234Sborman #ifdef convex 669*46809Sdab char *host; 67045234Sborman #endif 6716002Sroot { 6726002Sroot int on = 1; 67333271Sminshall #define TABBUFSIZ 512 67433271Sminshall char defent[TABBUFSIZ]; 67533271Sminshall char defstrs[TABBUFSIZ]; 67633271Sminshall #undef TABBUFSIZ 67733271Sminshall char *HE; 67833271Sminshall char *HN; 67933271Sminshall char *IM; 68038904Sborman void netflush(); 681*46809Sdab 68232400Sminshall /* 68338904Sborman * Initialize the slc mapping table. 68432400Sminshall */ 68538904Sborman get_slc_defaults(); 6866002Sroot 6878379Ssam /* 68838904Sborman * Do some tests where it is desireable to wait for a response. 68938904Sborman * Rather than doing them slowly, one at a time, do them all 69038904Sborman * at once. 6918379Ssam */ 69244363Sborman if (my_state_is_wont(TELOPT_SGA)) 69339503Sborman send_will(TELOPT_SGA, 1); 69412713Ssam /* 69527649Sminshall * Is the client side a 4.2 (NOT 4.3) system? We need to know this 69627649Sminshall * because 4.2 clients are unable to deal with TCP urgent data. 69727649Sminshall * 69827649Sminshall * To find out, we send out a "DO ECHO". If the remote system 69927649Sminshall * answers "WILL ECHO" it is probably a 4.2 client, and we note 70027649Sminshall * that fact ("WILL ECHO" ==> that the client will echo what 70127649Sminshall * WE, the server, sends it; it does NOT mean that the client will 70227649Sminshall * echo the terminal input). 70327649Sminshall */ 70439503Sborman send_do(TELOPT_ECHO, 1); 70527649Sminshall 70638904Sborman #ifdef LINEMODE 70744363Sborman if (his_state_is_wont(TELOPT_LINEMODE)) { 70838904Sborman /* Query the peer for linemode support by trying to negotiate 70938904Sborman * the linemode option. 71038904Sborman */ 71144363Sborman linemode = 0; 71238904Sborman editmode = 0; 71339503Sborman send_do(TELOPT_LINEMODE, 1); /* send do linemode */ 71438904Sborman } 71538904Sborman #endif /* LINEMODE */ 71638904Sborman 71727649Sminshall /* 71838904Sborman * Send along a couple of other options that we wish to negotiate. 71938904Sborman */ 72039503Sborman send_do(TELOPT_NAWS, 1); 72139503Sborman send_will(TELOPT_STATUS, 1); 72238904Sborman flowmode = 1; /* default flow control state */ 72339503Sborman send_do(TELOPT_LFLOW, 1); 72438904Sborman 72538904Sborman /* 72638904Sborman * Spin, waiting for a response from the DO ECHO. However, 72738904Sborman * some REALLY DUMB telnets out there might not respond 72838904Sborman * to the DO ECHO. So, we spin looking for NAWS, (most dumb 72938904Sborman * telnets so far seem to respond with WONT for a DO that 73038904Sborman * they don't understand...) because by the time we get the 73138904Sborman * response, it will already have processed the DO ECHO. 73238904Sborman * Kludge upon kludge. 73338904Sborman */ 73444363Sborman while (his_will_wont_is_changing(TELOPT_NAWS)) 73538904Sborman ttloop(); 73638904Sborman 73738904Sborman /* 73844363Sborman * But... 73944363Sborman * The client might have sent a WILL NAWS as part of its 74044363Sborman * startup code; if so, we'll be here before we get the 74144363Sborman * response to the DO ECHO. We'll make the assumption 74244363Sborman * that any implementation that understands about NAWS 74344363Sborman * is a modern enough implementation that it will respond 74444363Sborman * to our DO ECHO request; hence we'll do another spin 74544363Sborman * waiting for the ECHO option to settle down, which is 74644363Sborman * what we wanted to do in the first place... 74744363Sborman */ 74844363Sborman if (his_want_state_is_will(TELOPT_ECHO) && 74944363Sborman his_state_is_will(TELOPT_NAWS)) { 75044363Sborman while (his_will_wont_is_changing(TELOPT_ECHO)) 75144363Sborman ttloop(); 75244363Sborman } 75344363Sborman /* 75438995Sborman * On the off chance that the telnet client is broken and does not 75538995Sborman * respond to the DO ECHO we sent, (after all, we did send the 75638995Sborman * DO NAWS negotiation after the DO ECHO, and we won't get here 75738995Sborman * until a response to the DO NAWS comes back) simulate the 75838995Sborman * receipt of a will echo. This will also send a WONT ECHO 75938995Sborman * to the client, since we assume that the client failed to 76038995Sborman * respond because it believes that it is already in DO ECHO 76138995Sborman * mode, which we do not want. 76238995Sborman */ 76344363Sborman if (his_want_state_is_will(TELOPT_ECHO)) { 764*46809Sdab DIAG(TD_OPTIONS, 765*46809Sdab {sprintf(nfrontp, "td: simulating recv\r\n"); 766*46809Sdab nfrontp += strlen(nfrontp);}); 76739503Sborman willoption(TELOPT_ECHO); 76840242Sborman } 76938995Sborman 77038995Sborman /* 77138995Sborman * Finally, to clean things up, we turn on our echo. This 77238995Sborman * will break stupid 4.2 telnets out of local terminal echo. 77338995Sborman */ 77438995Sborman 77544363Sborman if (my_state_is_wont(TELOPT_ECHO)) 77639503Sborman send_will(TELOPT_ECHO, 1); 77738995Sborman 77838995Sborman /* 77945234Sborman * Turn on packet mode 78038904Sborman */ 78138904Sborman (void) ioctl(p, TIOCPKT, (char *)&on); 782*46809Sdab #if defined(LINEMODE) && defined(KLUDGELINEMODE) 78338904Sborman /* 78438904Sborman * Continuing line mode support. If client does not support 78538904Sborman * real linemode, attempt to negotiate kludge linemode by sending 78638904Sborman * the do timing mark sequence. 78738904Sborman */ 78838904Sborman if (lmodetype < REAL_LINEMODE) 78939503Sborman send_do(TELOPT_TM, 1); 790*46809Sdab #endif /* defined(LINEMODE) && defined(KLUDGELINEMODE) */ 79138904Sborman 79238904Sborman /* 79338904Sborman * Call telrcv() once to pick up anything received during 79438904Sborman * terminal type negotiation, 4.2/4.3 determination, and 79538904Sborman * linemode negotiation. 79638904Sborman */ 79738904Sborman telrcv(); 79838904Sborman 79938904Sborman (void) ioctl(f, FIONBIO, (char *)&on); 80038904Sborman (void) ioctl(p, FIONBIO, (char *)&on); 80140242Sborman #if defined(CRAY2) && defined(UNICOS5) 80238904Sborman init_termdriver(f, p, interrupt, sendbrk); 80338904Sborman #endif 80438904Sborman 80538904Sborman #if defined(SO_OOBINLINE) 80638904Sborman (void) setsockopt(net, SOL_SOCKET, SO_OOBINLINE, &on, sizeof on); 80738904Sborman #endif /* defined(SO_OOBINLINE) */ 80838904Sborman 80938904Sborman #ifdef SIGTSTP 81038904Sborman (void) signal(SIGTSTP, SIG_IGN); 81138904Sborman #endif 81238904Sborman #ifdef SIGTTOU 81338904Sborman /* 81438904Sborman * Ignoring SIGTTOU keeps the kernel from blocking us 81538904Sborman * in ttioct() in /sys/tty.c. 81638904Sborman */ 81738904Sborman (void) signal(SIGTTOU, SIG_IGN); 81838904Sborman #endif 81938904Sborman 82038904Sborman (void) signal(SIGCHLD, cleanup); 82138904Sborman 82240242Sborman #if defined(CRAY2) && defined(UNICOS5) 82338904Sborman /* 82438904Sborman * Cray-2 will send a signal when pty modes are changed by slave 82538904Sborman * side. Set up signal handler now. 82638904Sborman */ 82738904Sborman if ((int)signal(SIGUSR1, termstat) < 0) 82838904Sborman perror("signal"); 82938904Sborman else if (ioctl(p, TCSIGME, (char *)SIGUSR1) < 0) 83038904Sborman perror("ioctl:TCSIGME"); 83138904Sborman /* 83238904Sborman * Make processing loop check terminal characteristics early on. 83338904Sborman */ 83438904Sborman termstat(); 83538904Sborman #endif 83638904Sborman 83745234Sborman #ifdef TIOCNOTTY 83845234Sborman { 83945234Sborman register int t; 84045234Sborman t = open(_PATH_TTY, O_RDWR); 84145234Sborman if (t >= 0) { 84245234Sborman (void) ioctl(t, TIOCNOTTY, (char *)0); 84345234Sborman (void) close(t); 84445234Sborman } 84545234Sborman } 84640242Sborman #endif 84745234Sborman 848*46809Sdab #if defined(CRAY) && defined(NEWINIT) && defined(TIOCSCTTY) 84945234Sborman (void) setsid(); 85044363Sborman ioctl(p, TIOCSCTTY, 0); 85144363Sborman #endif 85238904Sborman 85338904Sborman /* 85412713Ssam * Show banner that getty never gave. 85527797Sminshall * 85633271Sminshall * We put the banner in the pty input buffer. This way, it 85733271Sminshall * gets carriage return null processing, etc., just like all 85833271Sminshall * other pty --> client data. 85912713Ssam */ 86027797Sminshall 86145234Sborman #if !defined(CRAY) || !defined(NEWINIT) 86245234Sborman if (getenv("USER")) 86345234Sborman hostinfo = 0; 86445234Sborman #endif 86538904Sborman 86633271Sminshall if (getent(defent, "default") == 1) { 86733271Sminshall char *getstr(); 86838904Sborman char *cp=defstrs; 86927649Sminshall 87038904Sborman HE = getstr("he", &cp); 87138904Sborman HN = getstr("hn", &cp); 87238904Sborman IM = getstr("im", &cp); 87333271Sminshall if (HN && *HN) 874*46809Sdab (void) strcpy(host_name, HN); 87538904Sborman if (IM == 0) 87638904Sborman IM = ""; 87733271Sminshall } else { 87845234Sborman IM = DEFAULT_IM; 87938904Sborman HE = 0; 88033271Sminshall } 881*46809Sdab edithost(HE, host_name); 88245234Sborman if (hostinfo && *IM) 88338904Sborman putf(IM, ptyibuf2); 88427797Sminshall 88538904Sborman if (pcc) 88638904Sborman (void) strncat(ptyibuf2, ptyip, pcc+1); 88738904Sborman ptyip = ptyibuf2; 88838904Sborman pcc = strlen(ptyip); 88940242Sborman #ifdef LINEMODE 89040242Sborman /* 89140242Sborman * Last check to make sure all our states are correct. 89240242Sborman */ 89340242Sborman init_termbuf(); 89440242Sborman localstat(); 89540242Sborman #endif /* LINEMODE */ 89633271Sminshall 897*46809Sdab DIAG(TD_REPORT, 898*46809Sdab {sprintf(nfrontp, "td: Entering processing loop\r\n"); 899*46809Sdab nfrontp += strlen(nfrontp);}); 90044363Sborman 90145234Sborman #ifdef convex 90245234Sborman startslave(host); 90345234Sborman #endif 90445234Sborman 9056002Sroot for (;;) { 90627185Sminshall fd_set ibits, obits, xbits; 9076002Sroot register int c; 9086002Sroot 90927185Sminshall if (ncc < 0 && pcc < 0) 91027185Sminshall break; 91127185Sminshall 91240242Sborman #if defined(CRAY2) && defined(UNICOS5) 91338904Sborman if (needtermstat) 91438904Sborman _termstat(); 91540242Sborman #endif /* defined(CRAY2) && defined(UNICOS5) */ 91627185Sminshall FD_ZERO(&ibits); 91727185Sminshall FD_ZERO(&obits); 91827185Sminshall FD_ZERO(&xbits); 9196002Sroot /* 9206002Sroot * Never look for input if there's still 9216002Sroot * stuff in the corresponding output buffer 9226002Sroot */ 92327185Sminshall if (nfrontp - nbackp || pcc > 0) { 92427185Sminshall FD_SET(f, &obits); 92527185Sminshall } else { 92627185Sminshall FD_SET(p, &ibits); 92727185Sminshall } 92827185Sminshall if (pfrontp - pbackp || ncc > 0) { 92927185Sminshall FD_SET(p, &obits); 93027185Sminshall } else { 93127185Sminshall FD_SET(f, &ibits); 93227185Sminshall } 93327185Sminshall if (!SYNCHing) { 93427185Sminshall FD_SET(f, &xbits); 93527185Sminshall } 93627185Sminshall if ((c = select(16, &ibits, &obits, &xbits, 93727185Sminshall (struct timeval *)0)) < 1) { 93827185Sminshall if (c == -1) { 93927185Sminshall if (errno == EINTR) { 94027185Sminshall continue; 94127185Sminshall } 94227185Sminshall } 9436002Sroot sleep(5); 9446002Sroot continue; 9456002Sroot } 9466002Sroot 9476002Sroot /* 94827185Sminshall * Any urgent data? 94927185Sminshall */ 95027185Sminshall if (FD_ISSET(net, &xbits)) { 95127185Sminshall SYNCHing = 1; 95227185Sminshall } 95327185Sminshall 95427185Sminshall /* 9556002Sroot * Something to read from the network... 9566002Sroot */ 95727185Sminshall if (FD_ISSET(net, &ibits)) { 95827649Sminshall #if !defined(SO_OOBINLINE) 95927185Sminshall /* 96027898Skarels * In 4.2 (and 4.3 beta) systems, the 96127185Sminshall * OOB indication and data handling in the kernel 96227185Sminshall * is such that if two separate TCP Urgent requests 96327185Sminshall * come in, one byte of TCP data will be overlaid. 96427185Sminshall * This is fatal for Telnet, but we try to live 96527185Sminshall * with it. 96627185Sminshall * 96727185Sminshall * In addition, in 4.2 (and...), a special protocol 96827185Sminshall * is needed to pick up the TCP Urgent data in 96927185Sminshall * the correct sequence. 97027185Sminshall * 97127185Sminshall * What we do is: if we think we are in urgent 97227185Sminshall * mode, we look to see if we are "at the mark". 97327185Sminshall * If we are, we do an OOB receive. If we run 97427185Sminshall * this twice, we will do the OOB receive twice, 97527185Sminshall * but the second will fail, since the second 97627185Sminshall * time we were "at the mark", but there wasn't 97727185Sminshall * any data there (the kernel doesn't reset 97827185Sminshall * "at the mark" until we do a normal read). 97927185Sminshall * Once we've read the OOB data, we go ahead 98027185Sminshall * and do normal reads. 98127185Sminshall * 98227185Sminshall * There is also another problem, which is that 98327185Sminshall * since the OOB byte we read doesn't put us 98427185Sminshall * out of OOB state, and since that byte is most 98527185Sminshall * likely the TELNET DM (data mark), we would 98627185Sminshall * stay in the TELNET SYNCH (SYNCHing) state. 98727185Sminshall * So, clocks to the rescue. If we've "just" 98827185Sminshall * received a DM, then we test for the 98927185Sminshall * presence of OOB data when the receive OOB 99027185Sminshall * fails (and AFTER we did the normal mode read 99127185Sminshall * to clear "at the mark"). 99227185Sminshall */ 99327185Sminshall if (SYNCHing) { 99427185Sminshall int atmark; 99527185Sminshall 99638904Sborman (void) ioctl(net, SIOCATMARK, (char *)&atmark); 99727185Sminshall if (atmark) { 99827185Sminshall ncc = recv(net, netibuf, sizeof (netibuf), MSG_OOB); 99927185Sminshall if ((ncc == -1) && (errno == EINVAL)) { 100027185Sminshall ncc = read(net, netibuf, sizeof (netibuf)); 100127983Sminshall if (sequenceIs(didnetreceive, gotDM)) { 100227185Sminshall SYNCHing = stilloob(net); 100327185Sminshall } 100427185Sminshall } 100527185Sminshall } else { 100627185Sminshall ncc = read(net, netibuf, sizeof (netibuf)); 10076002Sroot } 100827185Sminshall } else { 100927185Sminshall ncc = read(net, netibuf, sizeof (netibuf)); 101027185Sminshall } 101127185Sminshall settimer(didnetreceive); 101227649Sminshall #else /* !defined(SO_OOBINLINE)) */ 101327185Sminshall ncc = read(net, netibuf, sizeof (netibuf)); 101427649Sminshall #endif /* !defined(SO_OOBINLINE)) */ 101527185Sminshall if (ncc < 0 && errno == EWOULDBLOCK) 101627185Sminshall ncc = 0; 101727185Sminshall else { 101827185Sminshall if (ncc <= 0) { 101927185Sminshall break; 102027185Sminshall } 102127185Sminshall netip = netibuf; 102227185Sminshall } 1023*46809Sdab DIAG((TD_REPORT | TD_NETDATA), 1024*46809Sdab {sprintf(nfrontp, "td: netread %d chars\r\n", ncc); 1025*46809Sdab nfrontp += strlen(nfrontp);}); 1026*46809Sdab DIAG(TD_NETDATA, printdata("nd", netip, ncc)); 10276002Sroot } 10286002Sroot 10296002Sroot /* 10306002Sroot * Something to read from the pty... 10316002Sroot */ 103238904Sborman if (FD_ISSET(p, &ibits)) { 10336002Sroot pcc = read(p, ptyibuf, BUFSIZ); 1034*46809Sdab /* 1035*46809Sdab * On some systems, if we try to read something 1036*46809Sdab * off the master side before the slave side is 1037*46809Sdab * opened, we get EIO. 1038*46809Sdab */ 1039*46809Sdab if (pcc < 0 && (errno == EWOULDBLOCK || errno == EIO)) { 10406002Sroot pcc = 0; 1041*46809Sdab } else { 10426002Sroot if (pcc <= 0) 10436002Sroot break; 104440242Sborman #if !defined(CRAY2) || !defined(UNICOS5) 104538904Sborman #ifdef LINEMODE 104638904Sborman /* 104738904Sborman * If ioctl from pty, pass it through net 104838904Sborman */ 104938904Sborman if (ptyibuf[0] & TIOCPKT_IOCTL) { 105038904Sborman copy_termbuf(ptyibuf+1, pcc-1); 105138904Sborman localstat(); 105238904Sborman pcc = 1; 105338904Sborman } 1054*46809Sdab #endif /* LINEMODE */ 105537210Sminshall if (ptyibuf[0] & TIOCPKT_FLUSHWRITE) { 105638904Sborman netclear(); /* clear buffer back */ 105745234Sborman #ifndef NO_URGENT 105840242Sborman /* 105945234Sborman * There are client telnets on some 106040242Sborman * operating systems get screwed up 106140242Sborman * royally if we send them urgent 106245234Sborman * mode data. 106340242Sborman */ 106437210Sminshall *nfrontp++ = IAC; 106537210Sminshall *nfrontp++ = DM; 106637210Sminshall neturg = nfrontp-1; /* off by one XXX */ 106740242Sborman #endif 106837210Sminshall } 106944363Sborman if (his_state_is_will(TELOPT_LFLOW) && 107037210Sminshall (ptyibuf[0] & 107138904Sborman (TIOCPKT_NOSTOP|TIOCPKT_DOSTOP))) { 107238904Sborman (void) sprintf(nfrontp, "%c%c%c%c%c%c", 107337210Sminshall IAC, SB, TELOPT_LFLOW, 107437210Sminshall ptyibuf[0] & TIOCPKT_DOSTOP ? 1 : 0, 107537210Sminshall IAC, SE); 107637210Sminshall nfrontp += 6; 107737210Sminshall } 107833267Sminshall pcc--; 107933267Sminshall ptyip = ptyibuf+1; 108040242Sborman #else /* defined(CRAY2) && defined(UNICOS5) */ 108138904Sborman if (!uselinemode) { 108239531Sborman unpcc = pcc; 108339531Sborman unptyip = ptyibuf; 108439531Sborman pcc = term_output(&unptyip, ptyibuf2, 108539531Sborman &unpcc, BUFSIZ); 108638904Sborman ptyip = ptyibuf2; 108738904Sborman } else 108838904Sborman ptyip = ptyibuf; 108940242Sborman #endif /* defined(CRAY2) && defined(UNICOS5) */ 109038904Sborman } 10916002Sroot } 10926002Sroot 10936002Sroot while (pcc > 0) { 10946002Sroot if ((&netobuf[BUFSIZ] - nfrontp) < 2) 10956002Sroot break; 10966002Sroot c = *ptyip++ & 0377, pcc--; 10976002Sroot if (c == IAC) 10986002Sroot *nfrontp++ = c; 109940242Sborman #if defined(CRAY2) && defined(UNICOS5) 110038904Sborman else if (c == '\n' && 110144363Sborman my_state_is_wont(TELOPT_BINARY) && newmap) 110238904Sborman *nfrontp++ = '\r'; 110340242Sborman #endif /* defined(CRAY2) && defined(UNICOS5) */ 11046002Sroot *nfrontp++ = c; 110544363Sborman if ((c == '\r') && (my_state_is_wont(TELOPT_BINARY))) { 110627020Sminshall if (pcc > 0 && ((*ptyip & 0377) == '\n')) { 110727020Sminshall *nfrontp++ = *ptyip++ & 0377; 110827020Sminshall pcc--; 110927020Sminshall } else 111027020Sminshall *nfrontp++ = '\0'; 111127020Sminshall } 11126002Sroot } 111340242Sborman #if defined(CRAY2) && defined(UNICOS5) 111439531Sborman /* 111539531Sborman * If chars were left over from the terminal driver, 111639531Sborman * note their existence. 111739531Sborman */ 1118*46809Sdab if (!uselinemode && unpcc) { 111939531Sborman pcc = unpcc; 112039531Sborman unpcc = 0; 112139531Sborman ptyip = unptyip; 112239531Sborman } 112340242Sborman #endif /* defined(CRAY2) && defined(UNICOS5) */ 112439531Sborman 112527185Sminshall if (FD_ISSET(f, &obits) && (nfrontp - nbackp) > 0) 11266002Sroot netflush(); 11276002Sroot if (ncc > 0) 11286002Sroot telrcv(); 112927185Sminshall if (FD_ISSET(p, &obits) && (pfrontp - pbackp) > 0) 11306002Sroot ptyflush(); 11316002Sroot } 1132*46809Sdab cleanup(0); 113338904Sborman } /* end of telnet */ 11346002Sroot 113538904Sborman #ifndef TCSIG 113638904Sborman # ifdef TIOCSIG 113738904Sborman # define TCSIG TIOCSIG 113838904Sborman # endif 113938904Sborman #endif 11406002Sroot 114137212Sminshall /* 11426002Sroot * Send interrupt to process on other side of pty. 11436002Sroot * If it is in raw mode, just write NULL; 11446002Sroot * otherwise, write intr char. 11456002Sroot */ 1146*46809Sdab void 11476002Sroot interrupt() 11486002Sroot { 114938904Sborman ptyflush(); /* half-hearted */ 11506002Sroot 115138904Sborman #ifdef TCSIG 115238904Sborman (void) ioctl(pty, TCSIG, (char *)SIGINT); 115338904Sborman #else /* TCSIG */ 115438904Sborman init_termbuf(); 115540242Sborman *pfrontp++ = slctab[SLC_IP].sptr ? 115640242Sborman (unsigned char)*slctab[SLC_IP].sptr : '\177'; 115738904Sborman #endif /* TCSIG */ 11586002Sroot } 11596002Sroot 116027229Sminshall /* 116127229Sminshall * Send quit to process on other side of pty. 116227229Sminshall * If it is in raw mode, just write NULL; 116327229Sminshall * otherwise, write quit char. 116427229Sminshall */ 1165*46809Sdab void 116627229Sminshall sendbrk() 116727229Sminshall { 116827229Sminshall ptyflush(); /* half-hearted */ 116938904Sborman #ifdef TCSIG 117038904Sborman (void) ioctl(pty, TCSIG, (char *)SIGQUIT); 117138904Sborman #else /* TCSIG */ 117238904Sborman init_termbuf(); 117340242Sborman *pfrontp++ = slctab[SLC_ABORT].sptr ? 117440242Sborman (unsigned char)*slctab[SLC_ABORT].sptr : '\034'; 117538904Sborman #endif /* TCSIG */ 117627229Sminshall } 117727229Sminshall 1178*46809Sdab void 117938904Sborman sendsusp() 11806002Sroot { 118138904Sborman #ifdef SIGTSTP 118238904Sborman ptyflush(); /* half-hearted */ 118338904Sborman # ifdef TCSIG 118438904Sborman (void) ioctl(pty, TCSIG, (char *)SIGTSTP); 118538904Sborman # else /* TCSIG */ 118640242Sborman *pfrontp++ = slctab[SLC_SUSP].sptr ? 118740242Sborman (unsigned char)*slctab[SLC_SUSP].sptr : '\032'; 118838904Sborman # endif /* TCSIG */ 118938904Sborman #endif /* SIGTSTP */ 11906002Sroot } 11916002Sroot 119245234Sborman /* 119345234Sborman * When we get an AYT, if ^T is enabled, use that. Otherwise, 119445234Sborman * just send back "[Yes]". 119545234Sborman */ 1196*46809Sdab void 119745234Sborman recv_ayt() 119845234Sborman { 119945234Sborman #if defined(SIGINFO) && defined(TCSIG) 120045234Sborman if (slctab[SLC_AYT].sptr && *slctab[SLC_AYT].sptr != _POSIX_VDISABLE) { 120145234Sborman (void) ioctl(pty, TCSIG, (char *)SIGINFO); 120245234Sborman return; 120345234Sborman } 120445234Sborman #endif 120545234Sborman (void) strcpy(nfrontp, "\r\n[Yes]\r\n"); 120645234Sborman nfrontp += 9; 120745234Sborman } 120845234Sborman 1209*46809Sdab void 121038904Sborman doeof() 12116002Sroot { 121238904Sborman init_termbuf(); 12136002Sroot 121445234Sborman #if defined(LINEMODE) && defined(USE_TERMIO) && (VEOF == VMIN) 121540242Sborman if (!tty_isediting()) { 1216*46809Sdab extern char oldeofc; 121740242Sborman *pfrontp++ = oldeofc; 121840242Sborman return; 121940242Sborman } 122040242Sborman #endif 122140242Sborman *pfrontp++ = slctab[SLC_EOF].sptr ? 122240242Sborman (unsigned char)*slctab[SLC_EOF].sptr : '\004'; 12236002Sroot } 1224