145223Ssklower /* 245223Ssklower * X.29 server 345223Ssklower * 445223Ssklower * Frank Pronk (...!ubc-vision!pronk) 545223Ssklower * April, September 1984 645223Ssklower * 745223Ssklower * Laboratory for Computational Vision 845223Ssklower * University of British Columbia 945223Ssklower * Copyright (c) 1045223Ssklower */ 1145223Ssklower 1245223Ssklower #include <sys/param.h> 1345223Ssklower #include <sys/socket.h> 1445223Ssklower #include <sys/stat.h> 1545223Ssklower #include <sys/wait.h> 1645223Ssklower 1745223Ssklower #include <netccitt/x25.h> 1845223Ssklower 1945223Ssklower #include <errno.h> 2045223Ssklower #include <netdb.h> 2145223Ssklower #include <signal.h> 2245293Ssklower #include <sys/ioctl.h> 2345293Ssklower #include <sys/termios.h> 2445293Ssklower #include <paths.h> 2545223Ssklower 2645223Ssklower #include "../h/x29.h" 2745223Ssklower 2845223Ssklower #define BUFSIZ 1024 2945223Ssklower #define MAXARGS 10 /* maximum size of server argument list */ 3045223Ssklower 3145223Ssklower #define X25NET 0 /* no ITI parameters */ 3245223Ssklower #define CCITT1978 1 /* 1978 CCITT standard parameter set */ 3345223Ssklower #define CCITT1980 2 /* 1980 CCITT standard parameter set */ 3445223Ssklower 3545223Ssklower 3645223Ssklower char pibuf[BUFSIZ], fibuf[BUFSIZ]; 3745223Ssklower int pty, net; 3845223Ssklower extern char **environ; 3945223Ssklower extern int errno; 4045293Ssklower char line[MAXPATHLEN]; 4145223Ssklower char console[] = "/dev/console"; 4245223Ssklower short packet_size; 4345293Ssklower short debug; 4445223Ssklower char *tracefn; /* trace file name */ 4545223Ssklower char *server; 4645223Ssklower short send_banner; 47*45294Ssklower struct termios pt, old_pt; 4845223Ssklower struct sockaddr_x25 sock; 4945223Ssklower 5045223Ssklower int reapchild(); 5145223Ssklower struct net *lookup (); 5245223Ssklower 5345223Ssklower char ccitt1978_prof[] = { /* initial profile */ 5445223Ssklower Q_BIT, X29_SET_AND_READ_PARMS, 5545223Ssklower X29_ECHO_CODE, 1, /* echo on */ 5645223Ssklower X29_FORWARDING_SIGNAL_CODE, 126, /* forward on all cntl */ 5745223Ssklower X29_IDLE_TIMER_CODE, 0, /* off */ 5845223Ssklower X29_AUX_DEV_CONTROL_CODE, 0, /* off */ 5945223Ssklower X29_RECEIVE_NET_MSGS_CODE, 1, /* xmit network msgs */ 6045223Ssklower X29_BREAK_PROCEDURE_CODE, 21, 6145223Ssklower X29_PADDING_CODE, 0, /* off */ 6245223Ssklower X29_LINE_FOLDING_CODE, 0, /* off */ 6345223Ssklower X29_TRANSMISSION_SPEED_CODE, 0, 6445223Ssklower X29_XON_XOFF_CODE, 1, /* enable XON/XOFF */ 6545223Ssklower }; 6645223Ssklower 6745223Ssklower char ccitt1980_prof[] = { /* initial profile */ 6845223Ssklower Q_BIT, X29_SET_AND_READ_PARMS, 6945223Ssklower X29_ECHO_CODE, 1, /* echo on */ 7045223Ssklower X29_FORWARDING_SIGNAL_CODE, 126, /* forward on all cntl */ 7145223Ssklower X29_IDLE_TIMER_CODE, 0, /* off */ 7245223Ssklower X29_AUX_DEV_CONTROL_CODE, 0, /* off */ 7345223Ssklower X29_RECEIVE_NET_MSGS_CODE, 1, /* xmit network msgs */ 7445223Ssklower X29_BREAK_PROCEDURE_CODE, 21, 7545223Ssklower X29_PADDING_CODE, 0, /* off */ 7645223Ssklower X29_LINE_FOLDING_CODE, 0, /* off */ 7745223Ssklower X29_TRANSMISSION_SPEED_CODE, 0, 7845223Ssklower X29_XON_XOFF_CODE, 1, /* enable XON/XOFF */ 7945223Ssklower 8045223Ssklower X29_LF_AFTER_CR, 4, /* lf after cr from terminal */ 8145223Ssklower X29_EDITING, 1, /* on */ 8245223Ssklower X29_CHARACTER_DELETE, CERASE, 8345223Ssklower X29_LINE_DELETE, CKILL, 8445223Ssklower X29_LINE_DISPLAY, CRPRNT, 8545223Ssklower }; 8645223Ssklower 8745223Ssklower char datapac_prof[] = { /* Canadian X.25 network */ 8845223Ssklower Q_BIT, X29_SET_AND_READ_PARMS, 8945223Ssklower X29_ECHO_CODE, 1, /* echo on */ 9045223Ssklower X29_FORWARDING_SIGNAL_CODE, 126, /* forward on all cntl */ 9145223Ssklower X29_IDLE_TIMER_CODE, 0, /* off */ 9245223Ssklower X29_AUX_DEV_CONTROL_CODE, 0, /* off */ 9345223Ssklower X29_RECEIVE_NET_MSGS_CODE, 1, /* xmit network msgs */ 9445223Ssklower X29_BREAK_PROCEDURE_CODE, 21, 9545223Ssklower X29_PADDING_CODE, 0, /* off */ 9645223Ssklower X29_LINE_FOLDING_CODE, 0, /* off */ 9745223Ssklower X29_TRANSMISSION_SPEED_CODE, 0, 9845223Ssklower X29_XON_XOFF_CODE, 1, /* enable XON/XOFF */ 9945223Ssklower 10045223Ssklower X29_LF_AFTER_CR, 4, /* lf after cr from terminal */ 10145223Ssklower X29_EDITING, 1, /* on */ 10245223Ssklower X29_CHARACTER_DELETE, CERASE, 10345223Ssklower X29_LINE_DELETE, CKILL, 10445223Ssklower X29_LINE_DISPLAY, CRPRNT, 10545223Ssklower 10645223Ssklower /* 10745223Ssklower * This rubbish can be removed when Datapac 10845223Ssklower * adopts the 1980 standard parameter set. 10945223Ssklower */ 11045223Ssklower 11145223Ssklower 0, 0, /* national parameter marker */ 11245223Ssklower 123, 0, /* parity off */ 11345223Ssklower }; 11445223Ssklower 11545223Ssklower struct net { 11645223Ssklower char *n_name; /* generic name */ 11745223Ssklower short n_type; /* see defines above */ 11845223Ssklower char *n_profile; /* initial profile */ 11945223Ssklower short n_proflen; /* length of n_profile */ 12045223Ssklower } *netp, nets[] = { 12145223Ssklower "x.25", X25NET, 0, 0, 12245223Ssklower "1978", CCITT1978, ccitt1978_prof, sizeof(ccitt1978_prof), 12345223Ssklower "ccitt1978", CCITT1978, ccitt1978_prof, sizeof(ccitt1978_prof), 12445223Ssklower "1980", CCITT1980, ccitt1980_prof, sizeof(ccitt1980_prof), 12545223Ssklower "ccitt1980", CCITT1980, ccitt1980_prof, sizeof(ccitt1980_prof), 12645223Ssklower "datapac", CCITT1980, datapac_prof, sizeof(datapac_prof), 12745223Ssklower 0, 0, 0, 0 12845223Ssklower }; 12945223Ssklower 13045223Ssklower main(argc, argv) 13145223Ssklower register char **argv; 13245223Ssklower { 13345223Ssklower register int s, pid; 13445223Ssklower register char *p; 13545223Ssklower 13645223Ssklower /* 13745223Ssklower * If this host doesn't support X.25, give up. 13845223Ssklower */ 13945223Ssklower s = socket(AF_CCITT, SOCK_STREAM, 0); 14045223Ssklower if (s < 0 && errno == EPROTONOSUPPORT) 14145223Ssklower fatal(2, "X.25 is not supported on this machine"); 14245223Ssklower close(s); 14345223Ssklower netp = lookup ("ccitt1978"); 14445223Ssklower sock.x25_family = AF_CCITT; 14545293Ssklower sock.x25_len = sizeof(sock); 14645223Ssklower sock.x25_opts.op_flags = X25_MQBIT; 14745223Ssklower sock.x25_udata[0] = ITI_CALL; 14845223Ssklower sock.x25_udlen = 4; 14945223Ssklower 15045223Ssklower for (argv++; argc > 1; argc--, argv++) 15145223Ssklower if (**argv == '-') 15245223Ssklower for (p = *argv+1; *p; p++) 15345223Ssklower switch (*p) { 15445223Ssklower case 'b': 15545223Ssklower send_banner++; 15645223Ssklower break; 15745223Ssklower 15845223Ssklower case 'c': 15945223Ssklower if (argc > 1) { 16045223Ssklower argc--; argv++; 16145223Ssklower if ((netp = lookup (*argv)) == 0) 16245223Ssklower fatal(1, "Unknown network type"); 16345223Ssklower } 16445223Ssklower break; 16545223Ssklower 16645223Ssklower case 'p': 16745223Ssklower if (argc > 1) { 16845223Ssklower argc--; argv++; 16945223Ssklower strcpy (sock.x25_udata, *argv); 17045223Ssklower } 17145223Ssklower break; 17245223Ssklower 17345223Ssklower case 'r': 17445223Ssklower sock.x25_opts.op_flags |= X25_REVERSE_CHARGE; 17545223Ssklower break; 17645223Ssklower 17745293Ssklower case 'd': 17845293Ssklower debug++; 17945293Ssklower break; 18045293Ssklower 18145223Ssklower case 't': 18245223Ssklower if (argc > 1) { 18345223Ssklower argc--; argv++; 18445223Ssklower tracefn = *argv; 18545223Ssklower } 18645223Ssklower else fatal(1, "missing trace file"); 18745223Ssklower break; 18845223Ssklower 18945223Ssklower default: 19045223Ssklower fatal (1, "usage: x29d -b -c nettype -p protocol -r -t trace_file server"); 19145223Ssklower } 19245223Ssklower else 19345223Ssklower server = *argv; 19445223Ssklower if (server == 0) 19545223Ssklower fatal (1, "no server specified"); 19645293Ssklower if (debug == 0) 19745293Ssklower daemon(0, 0); 19845223Ssklower 199*45294Ssklower while ((s = socket(AF_CCITT, SOCK_STREAM, 0)) < 0) 20045223Ssklower sleep(60); 20145223Ssklower while (bind(s, (caddr_t)&sock, sizeof (sock)) < 0) 20245223Ssklower sleep(60); 20345223Ssklower signal(SIGCHLD, reapchild); 20445223Ssklower listen(s, 5); 20545223Ssklower 20645223Ssklower for (;;) { 207*45294Ssklower s truct sockaddr_x25 from; 20845223Ssklower int fromlen = sizeof (from); 20945223Ssklower 21045223Ssklower if ((net = accept(s, (caddr_t)&from, &fromlen)) < 0) { 21145223Ssklower if (errno != EINTR) 21245223Ssklower sleep (60); 21345223Ssklower continue; 21445223Ssklower } 21545223Ssklower while ((pid = fork()) < 0) 21645223Ssklower sleep(60); 21745223Ssklower if (pid == 0) { 21845223Ssklower signal(SIGCHLD, SIG_DFL); 21945223Ssklower doit(&from); 22045223Ssklower } 22145223Ssklower close(net); 22245223Ssklower } 22345223Ssklower /*NOTREACHED*/ 22445223Ssklower } 22545223Ssklower 22645223Ssklower struct net * 22745223Ssklower lookup (name) 22845223Ssklower char *name; 22945223Ssklower { 23045223Ssklower register struct net *np; 23145223Ssklower 23245223Ssklower for (np = nets; np->n_name; np++) 23345223Ssklower if (strcmp (np->n_name, name) == 0) 23445223Ssklower return (np); 23545223Ssklower return (0); 23645223Ssklower } 23745223Ssklower 23845223Ssklower reapchild() 23945223Ssklower { 24045223Ssklower union wait status; 24145223Ssklower 24245223Ssklower while (wait3(&status, WNOHANG, 0) > 0) 24345223Ssklower ; 24445223Ssklower } 24545223Ssklower 24645223Ssklower char *envinit[] = { "TERM=ccitt", 0 }; 24745223Ssklower int cleanup(); 24845293Ssklower struct termios term; 24945223Ssklower 25045223Ssklower /* 25145223Ssklower * Get a pty, scan input lines. 25245223Ssklower */ 25345223Ssklower doit(who) 25445223Ssklower struct sockaddr_x25 *who; 25545223Ssklower { 25645223Ssklower register char *cp; 25745293Ssklower int i, p, t; 25845223Ssklower 25945223Ssklower packet_size = 1 << who->x25_opts.op_psize; 26045293Ssklower i = forkpty(&pty, line, &term, 0); 26145293Ssklower if (i > 0) 26245293Ssklower x29d(); 26345293Ssklower if (i < 0) 26445223Ssklower fatalperror("fork", errno); 26545223Ssklower environ = envinit; 26645223Ssklower call_server (who); 26745223Ssklower /*NOTREACHED*/ 26845223Ssklower } 26945223Ssklower 27045223Ssklower call_server (who) 27145223Ssklower struct sockaddr_x25 *who; 27245223Ssklower { 27345223Ssklower register struct hostent *hp = 0; 27445223Ssklower register char *p, **ap; 27545223Ssklower char *args[MAXARGS]; 27645223Ssklower struct stat st; 27745223Ssklower struct hostent *getx25hostbyaddr(); 27845223Ssklower int ccitt = 0; 27945223Ssklower 28045223Ssklower p = server; 28145223Ssklower while (*p && *p != ' ' && *p != '\t') /* split program from args */ 28245223Ssklower p++; 28345223Ssklower if (*p) 28445223Ssklower *p++ = '\0'; 28545223Ssklower ap = args; 28645223Ssklower while (*p) { 28745223Ssklower while (*p == ' ' || *p == '\t') 28845223Ssklower p++; 28945223Ssklower if (ap < &args[MAXARGS-2]) 29045223Ssklower *ap++ = p; 29145223Ssklower if (strcmp(p, "-ccitt") == 0) 29245223Ssklower ccitt = 1; 29345223Ssklower while (*p && *p != ' ' && *p != '\t') 29445223Ssklower p++; 29545223Ssklower if (*p) 29645223Ssklower *p++ = '\0'; 29745223Ssklower } 29845223Ssklower if (stat (server, &st) < 0) 29945223Ssklower fatalperror (server, errno); 30045223Ssklower /* 30145223Ssklower * For security: if running as root, switch to user 30245223Ssklower * and group id of server. This prevents privately 30345223Ssklower * maintainted or bogus servers from getting super- 30445223Ssklower * user permissions. 30545223Ssklower */ 30645223Ssklower if (getuid() == 0) { 30745223Ssklower setgid (st.st_gid); 30845223Ssklower setuid (st.st_uid); 30945223Ssklower } 31045223Ssklower if (hp = getx25hostbyaddr (who->x25_addr)) 31145223Ssklower *ap++ = hp->h_name; 31245223Ssklower else 31345223Ssklower *ap++ = (char *)who->x25_addr; 31445223Ssklower /* 31545223Ssklower * If the -ccitt flag was given, add another argument 31645223Ssklower * to tell login if charging is being reversed or not. 31745223Ssklower */ 31845223Ssklower if (ccitt) 31945223Ssklower *ap++ = (who->x25_opts.op_flags & X25_REVERSE_CHARGE) ? "y" : "n"; 32045223Ssklower *ap = 0; 32145223Ssklower execv (server, args); 32245223Ssklower fatalperror (server, errno); 32345223Ssklower /*NOTREACHED*/ 32445223Ssklower } 32545223Ssklower 32645223Ssklower fatal(f, msg) 32745223Ssklower int f; 32845223Ssklower char *msg; 32945223Ssklower { 33045223Ssklower register char *p; 33145223Ssklower char buf[BUFSIZ], *index(); 33245223Ssklower 33345223Ssklower p = buf; 33445223Ssklower if (f == net) 33545223Ssklower *p++ = 0; 33645223Ssklower strcpy(p, "x29d: "); 33745223Ssklower strcat(p, msg); 33845223Ssklower strcat(p, "\n"); 33945223Ssklower (void) write(f, p, (index(p, '\n')-p)+1); 34045223Ssklower exit(1); 34145223Ssklower } 34245223Ssklower 34345223Ssklower fatalperror(msg, err) 34445223Ssklower char *msg; 34545223Ssklower { 34645223Ssklower char buf[BUFSIZ]; 34745223Ssklower extern char *sys_errlist[]; 34845223Ssklower 34945223Ssklower strcpy(buf, msg); 35045223Ssklower strcat(buf, ": "); 35145223Ssklower strcat(buf, sys_errlist[err]); 35245223Ssklower fatal(net, buf); 35345223Ssklower } 35445223Ssklower 35545223Ssklower /* 35645223Ssklower * Main loop. Select from pty and network, and 35745223Ssklower * hand data to iti receiver. 35845223Ssklower */ 35945223Ssklower x29d() 36045223Ssklower { 36145223Ssklower register int pcc, fcc, cc; 36245223Ssklower register char *fbp; 36345223Ssklower int pgrp, x25_interrupt(), on = 1; 36445223Ssklower char hostname[32]; 36545223Ssklower 36645223Ssklower ioctl(net, FIONBIO, (char *)&on); 36745223Ssklower ioctl(pty, FIONBIO, (char *)&on); 368*45294Ssklower /*ioctl(pty, TIOCREMECHO, (char *)&on); /* enable special pty mode */ 369*45294Ssklower /* new equivalent is no processing in pty, no echo, but let 370*45294Ssklower user set modes and have either remote end do line mode processing 371*45294Ssklower or do it in daemon */ 372*45294Ssklower ioctl(pty, TIOCEXT, (char *)&on); 37345223Ssklower ioctl(pty, TIOCPKT, (char *)&on); 374*45294Ssklower ioctl(pty, TIOCGETA, (char *)&pt); 37545223Ssklower signal(SIGPIPE, SIG_IGN); /* why not cleanup? --kwl */ 37645223Ssklower signal(SIGTSTP, SIG_IGN); 37745223Ssklower signal(SIGCHLD, cleanup); 37845223Ssklower signal(SIGHUP, cleanup); 37945223Ssklower 38045223Ssklower signal(SIGTTOU, SIG_IGN); 38145223Ssklower signal(SIGURG, x25_interrupt); /* for out-of-band data */ 38245223Ssklower 38345223Ssklower if (netp->n_proflen) 38445223Ssklower (void) write(net, netp->n_profile, netp->n_proflen); 38545223Ssklower 38645223Ssklower /* 38745223Ssklower * Show banner that getty never gave. 38845223Ssklower */ 38945223Ssklower if (send_banner) { 39045223Ssklower gethostname(hostname, sizeof (hostname)); 39145223Ssklower #ifdef BSD4_3 39245223Ssklower strcpy(pibuf+1, "\r\n\r\n4.3 BSD UNIX ("); 39345223Ssklower #else 39445223Ssklower strcpy(pibuf+1, "\r\n\r\n4.2 BSD UNIX ("); 39545223Ssklower #endif 39645223Ssklower strcat(pibuf+1, hostname); 39745223Ssklower strcat(pibuf+1, ")\r\n\r\n"); 39845223Ssklower pcc = strlen(pibuf+1) + 1; 39945223Ssklower } else 40045223Ssklower pcc = 0; 40145223Ssklower 40245223Ssklower fcc = 0; 40345223Ssklower for (;;) { 40445223Ssklower int ibits, obits; 40545223Ssklower 40645223Ssklower ibits = obits = 0; 40745223Ssklower /* 40845223Ssklower * Never look for input if there's still 40945223Ssklower * stuff in the corresponding output buffer 41045223Ssklower */ 41145223Ssklower if (fcc >= 0) /* net connection alive? */ 41245223Ssklower if (fcc && pcc >= 0) /* output pending? */ 41345223Ssklower obits |= (1 << pty); 41445223Ssklower else 41545223Ssklower if (pcc >= 0) /* pty still alive? */ 41645223Ssklower ibits |= (1 << net); 41745223Ssklower if (pcc >= 0) /* pty connection alive? */ 41845223Ssklower if (pcc && fcc >= 0) /* output pending? */ 41945223Ssklower obits |= (1 << net); 42045223Ssklower else 42145223Ssklower if (fcc >= 0) /* net still alive? */ 42245223Ssklower ibits |= (1 << pty); 423*45294Ssklower if (ibits == 0 && obits == 0) 42445223Ssklower break; 42545223Ssklower (void) select(16, &ibits, &obits, (int *)0, 0); 42645223Ssklower if (ibits == 0 && obits == 0) { 42745223Ssklower sleep(5); 42845223Ssklower continue; 42945223Ssklower } 43045223Ssklower 43145223Ssklower /* 43245223Ssklower * Something to read from the network... 43345223Ssklower */ 434*45294Ssklower if (fcc == 0 && (ibits & (1 << net))) { 43545223Ssklower fcc = read(net, fibuf, BUFSIZ); 43645223Ssklower fbp = fibuf+1; 43745223Ssklower if (fcc < 0 && errno == EWOULDBLOCK) 43845223Ssklower fcc = 0; 439*45294Ssklower else if (fcc <= 0) 44045223Ssklower fcc = -1; 44145223Ssklower else { 44245223Ssklower if (tracefn) 44345223Ssklower x29d_trace("netread", fibuf, fcc); 444*45294Ssklower if (fibuf[0] & Q_BIT) { 44545223Ssklower x29_qbit(fcc); 44645223Ssklower fcc = 0; 44745223Ssklower } else 44845223Ssklower fcc--; 44945223Ssklower } 45045223Ssklower } 45145223Ssklower 45245223Ssklower /* 45345223Ssklower * Something to read from the pty... 45445223Ssklower */ 45545223Ssklower if (ibits & (1 << pty)) { 45645223Ssklower pcc = read(pty, pibuf, packet_size+1); 45745223Ssklower if (pcc < 0 && errno == EWOULDBLOCK) 45845223Ssklower pcc = 0; 45945223Ssklower else if (pcc <= 0) 46045223Ssklower pcc = -1; 461*45294Ssklower else if (pibuf[0] != 0) { /* non-data packet */ 462*45294Ssklower if (pibuf[0] & TIOCPKT_IOCTL) { 463*45294Ssklower if (--pcc > sizeof(pt)) 464*45294Ssklower pcc = sizeof(pt); 465*45294Ssklower old_pt = pt; 466*45294Ssklower bcopy(pibuf + 1, (char *)&pt, pcc); 46745223Ssklower pcc = set_x29_parameters(); 468*45294Ssklower } else 46945223Ssklower pcc = 0; 47045223Ssklower } else /* data packet */ 47145223Ssklower pibuf[0] = 0; 47245223Ssklower } 47345223Ssklower 47445223Ssklower if ((obits & (1<<net)) && pcc > 0) 475*45294Ssklower if ((cc = write(net, pibuf, pcc)) == pcc) { 476*45294Ssklower if (tracefn) 47745223Ssklower x29d_trace("netwrite", pibuf, pcc); 47845223Ssklower pcc = 0; 47945223Ssklower } else { 48045223Ssklower extern char *sys_errlist[]; 48145223Ssklower 482*45294Ssklower if (tracefn) 48345223Ssklower x29d_trace("netwrite", 48445223Ssklower sys_errlist[errno], 48545223Ssklower strlen(sys_errlist[errno])); 48645223Ssklower 48745223Ssklower } 48845223Ssklower 48945223Ssklower if ((obits & (1 << pty)) && fcc > 0) { 490*45294Ssklower cc = ptywrite(fbp, fcc); 49145223Ssklower if (cc > 0) { 49245223Ssklower fcc -= cc; 49345223Ssklower fbp += cc; 49445223Ssklower } 49545223Ssklower } 49645223Ssklower } 49745223Ssklower cleanup(); 49845223Ssklower } 49945223Ssklower 50045223Ssklower 50145223Ssklower /* 50245223Ssklower * Send interrupt to process on other side of pty. 50345223Ssklower * If it is in raw mode, just write NULL; 50445223Ssklower * otherwise, write intr char. 50545223Ssklower */ 50645223Ssklower 50745223Ssklower x25_interrupt() 50845223Ssklower { 50945293Ssklower struct termios tt; 51045223Ssklower int zero = 0; 51145223Ssklower 51245223Ssklower signal(SIGURG, x25_interrupt); 51345293Ssklower tcgetattr(pty, &tt); 51445293Ssklower if (tt.c_lflag & ISIG) { 51545293Ssklower tcsetattr(pty, TCSAFLUSH, &tt); 51645293Ssklower (void) write(pty, &tt.c_cc[VINTR], 1); 51745293Ssklower } else 51845223Ssklower (void) write(pty, "\0", 1); 51945223Ssklower } 52045223Ssklower 52145223Ssklower cleanup() 52245223Ssklower { 52345293Ssklower char *p; 52445223Ssklower 52545293Ssklower p = line + sizeof(_PATH_DEV) - 1; 52645293Ssklower if (logout(p)) 52745293Ssklower logwtmp(p, "", ""); 52845293Ssklower (void)chmod(line, 0666); 52945293Ssklower (void)chown(line, 0, 0); 53045293Ssklower *p = 'p'; 53145293Ssklower (void)chmod(line, 0666); 53245293Ssklower (void)chown(line, 0, 0); 53345293Ssklower shutdown(net, 2); 53445223Ssklower exit(1); 53545223Ssklower } 53645223Ssklower 53745223Ssklower /* 53845223Ssklower * Map unix tty modes and special characters 53945223Ssklower * into x29 parameters. 54045223Ssklower */ 54145223Ssklower 54245223Ssklower set_x29_parameters() 54345223Ssklower { 54445223Ssklower register char *p; 545*45294Ssklower int f; 546*45294Ssklower char *lim = p + sizeof (pt); 54745223Ssklower 54845223Ssklower if (netp->n_type == X25NET) 54945223Ssklower return (0); 550*45294Ssklower if ((old_pt.c_lflag & ICANON) != (pt.c_lflag & ICANON)) { 551*45294Ssklower f = pt.c_lflag & ICANON; 552*45294Ssklower ioctl(pty, TIOCEXT, &f); 553*45294Ssklower /* this precipitates more junk of the same 554*45294Ssklower * sort that caused our call here, but we can't 555*45294Ssklower * turn it off since something may be going on in our progeny. 556*45294Ssklower * 557*45294Ssklower * Instead, we'll check the next time around to see if nothing 558*45294Ssklower * has changed, and skip informing the network. 559*45294Ssklower */ 560*45294Ssklower } 561*45294Ssklower if (bcmp((char *)&pt, (char *)&old_pt, sizeof (pt)) == 0) 562*45294Ssklower return; 56345223Ssklower p = pibuf; 56445223Ssklower *p++ = Q_BIT; 56545223Ssklower *p++ = X29_SET_PARMS; 56645293Ssklower /* *p++ = X29_ESCAPE_TO_CMD_CODE; *p++ = (f & (RAW|CBREAK)) == 0;*/ 567*45294Ssklower *p++ = X29_ESCAPE_TO_CMD_CODE; *p++ = (pt.c_lflag & ICANON) != 0; 56845223Ssklower 569*45294Ssklower *p++ = X29_ECHO_CODE; *p++ = (pt.c_lflag & ECHO) != 0; 57045293Ssklower *p++ = X29_FORWARDING_SIGNAL_CODE; 571*45294Ssklower *p++ = (pt.c_lflag & ISIG) ? 0 : 126; 57245293Ssklower 57345223Ssklower /* 57445223Ssklower * The value of 10 (0.5 seconds) for the idle timer when 57545223Ssklower * in raw or cbreak mode is a compromise value. For good 57645223Ssklower * interactive response this value should be as low as 57745223Ssklower * possible; for reasonable efficiency with file transfers 57845223Ssklower * this value should be at fairly high. This number should 57945223Ssklower * be changed to suit local requirements. 58045223Ssklower */ 58145223Ssklower 58245293Ssklower /**p++ = X29_IDLE_TIMER_CODE; *p++ = (f & (RAW|CBREAK)) ? 10 : 0;*/ 583*45294Ssklower *p++ = X29_IDLE_TIMER_CODE; *p++ = (pt.c_lflag & ICANON) ? 0 : 10; 58445293Ssklower 58545293Ssklower /**p++ = X29_AUX_DEV_CONTROL_CODE;*p++ = (f & TANDEM) != 0;*/ 586*45294Ssklower *p++ = X29_AUX_DEV_CONTROL_CODE;*p++ = (pt.c_iflag & IXOFF) != 0; 587*45294Ssklower *p++ = X29_XON_XOFF_CODE; *p++ = (pt.c_iflag & IXON) != 0; 588*45294Ssklower if (netp->n_type == CCITT1980) { 58945293Ssklower *p++ = X29_LF_AFTER_CR; 59045293Ssklower /* *p++ = (f & (RAW|CBREAK) || (f & ECHO) == 0) ? 0 : 4; */ 591*45294Ssklower *p++ = ((pt.c_lflag & (ICANON | ECHO)) != (ICANON | ECHO)) ? 59245293Ssklower 0 : 4; 59345223Ssklower 594*45294Ssklower *p++ = X29_EDITING; *p++ = (pt.c_lflag & ICANON) != 0; 59545293Ssklower #define ctlchar(x) \ 596*45294Ssklower (0 == (pt.c_lflag & ICANON) || pt.c_cc[x] == _POSIX_VDISABLE) ? 0 : pt.c_cc[x] 59745293Ssklower *p++ = X29_CHARACTER_DELETE; *p++ = ctlchar(VERASE); 59845293Ssklower *p++ = X29_LINE_DELETE; *p++ = ctlchar(VKILL); 59945293Ssklower *p++ = X29_LINE_DISPLAY; *p++ = ctlchar(VREPRINT); 60045223Ssklower } 601*45294Ssklower #undef ctlchar 60245223Ssklower return (p - pibuf); 60345223Ssklower } 60445223Ssklower 605*45294Ssklower /* Have to be careful writing to pty. The pad will forward control 606*45294Ssklower * characters without necessarily sending an interrupt so if ISIG and 607*45294Ssklower * ICANNON are set, must inspect line for quit or interrupt or suspend. 608*45294Ssklower */ 609*45294Ssklower ptywrite(buf, n) 610*45294Ssklower char *buf; 611*45294Ssklower int n; 612*45294Ssklower { 613*45294Ssklower register char *cp, *lim; 614*45294Ssklower char *last; 615*45294Ssklower #define is_ctl(x) (pt.c_cc[x] == *(cc_t *)cp) 616*45294Ssklower 617*45294Ssklower if ((pt.c_lflag & EXTPROC) && (pt.c_lflag & ISIG)) { 618*45294Ssklower for (cp = buf, lim = buf + n; cp < lim; cp ++) { 619*45294Ssklower if (is_ctl(VLNEXT)) 620*45294Ssklower { cp++; continue; } 621*45294Ssklower if (is_ctl(VSUSP) || is_ctl(VDSUSP) || 622*45294Ssklower is_ctl(VINTR) || is_ctl(VQUIT)) { 623*45294Ssklower int onoff = 0; 624*45294Ssklower tcflag_t old_echo = pt.c_lflag & ECHO; 625*45294Ssklower 626*45294Ssklower ioctl(pty, TIOCPKT, (char *)&onoff); 627*45294Ssklower ioctl(pty, FIONBIO, (char *)&onoff); 628*45294Ssklower ioctl(pty, TIOCEXT, (char *)&onoff); 629*45294Ssklower if (old_echo) { 630*45294Ssklower pt.c_lflag &= ~ECHO; 631*45294Ssklower ioctl(pty, TIOCSETA, (char *)&pt); 632*45294Ssklower } 633*45294Ssklower n = write(pty, buf, n); 634*45294Ssklower onoff = 1; 635*45294Ssklower if (old_echo) { 636*45294Ssklower pt.c_lflag |= ECHO; 637*45294Ssklower ioctl(pty, TIOCSETA, (char *)&pt); 638*45294Ssklower } 639*45294Ssklower ioctl(pty, TIOCEXT, (char *)&onoff); 640*45294Ssklower ioctl(pty, FIONBIO, (char *)&onoff); 641*45294Ssklower ioctl(pty, TIOCPKT, (char *)&onoff); 642*45294Ssklower return (n); 643*45294Ssklower } 644*45294Ssklower } 645*45294Ssklower } 646*45294Ssklower return write(pty, buf, n); 647*45294Ssklower } 648*45294Ssklower 64945223Ssklower /* 65045223Ssklower * Process Q BIT (control) packets from the net. 65145223Ssklower * The only message that we are interested in are 65245223Ssklower * those indicating output is being discarded. 65345223Ssklower */ 65445223Ssklower 65545223Ssklower x29_qbit(n) 65645223Ssklower { 65745223Ssklower register char *p; 65845223Ssklower 65945223Ssklower switch (fibuf[1]) { 66045223Ssklower case X29_SET_PARMS: 66145223Ssklower case X29_SET_AND_READ_PARMS: 66245223Ssklower case X29_PARAMETER_INDICATION: 66345223Ssklower case X29_INDICATION_OF_BREAK: 664*45294Ssklower for (p = &fibuf[2]; p < fibuf+n; p++) { 665*45294Ssklower if (*p == X29_TRANSMISSION_SPEED_CODE) { 66645223Ssklower static char speeds[] = { 66745223Ssklower B110, B0, B300, B1200, B600, 66845223Ssklower B0, B0, B0, B0, B0, B0, B0, 66945223Ssklower B2400, B4800, B9600, EXTA }; 67045223Ssklower 671*45294Ssklower if (*++p >= 0 && *p < sizeof(speeds)) { 672*45294Ssklower cfsetspeed(&pt, speeds[*p]); 673*45294Ssklower tcsetattr(pty, TCSANOW, &pt); 67445223Ssklower } 675*45294Ssklower } else if (*p == X29_DISCARD_OUTPUT_CODE && *++p != 0) { 67645223Ssklower char message[4]; 67745223Ssklower 67845223Ssklower /* 67945223Ssklower * Always re-enable normal output 68045223Ssklower */ 68145223Ssklower message[0] = Q_BIT; 68245223Ssklower message[1] = X29_SET_PARMS; 68345223Ssklower message[2] = X29_DISCARD_OUTPUT_CODE; 68445223Ssklower message[3] = 0; 68545223Ssklower (void) write(net, message, sizeof(message)); 686*45294Ssklower if (tracefn) 68745223Ssklower x29d_trace("netwrite", message, 4); 68845223Ssklower } 68945223Ssklower } 69045223Ssklower return; 69145223Ssklower 69245223Ssklower default: { 69345223Ssklower register char *p2; 69445223Ssklower char buf[BUFSIZ*4]; 69545223Ssklower static int fd; 69645223Ssklower 69745223Ssklower /* 69845223Ssklower * Bad news - we received an x29 error message or 69945223Ssklower * some other unknown packet. Dump the contents 70045223Ssklower * of the packet on the console. 70145223Ssklower */ 70245223Ssklower p = buf; 703*45294Ssklower for (p2 = "x29d: unknown q-bit packet: "; *p++ = *p2++; ); 704*45294Ssklower for (p2 = fibuf+1; p2 < fibuf+n; p2++) 705*45294Ssklower if (*p2 >= ' ' && *p2 < 0177) 70645223Ssklower *p++ = *p2; 70745223Ssklower else { 70845223Ssklower *p++ = '\\'; 70945223Ssklower *p++ = ((*p2 & 0300) >> 6) + '0'; 71045223Ssklower *p++ = ((*p2 & 070) >> 3) + '0'; 71145223Ssklower *p++ = (*p2 & 07) + '0'; 71245223Ssklower } 71345223Ssklower *p++ = '\n'; 714*45294Ssklower if (fd <= 0) 71545223Ssklower fd = open(console, 1); 71645223Ssklower (void) write(fd, buf, p-buf); 71745223Ssklower } 71845223Ssklower } 71945223Ssklower } 72045223Ssklower 72145223Ssklower x29d_trace(s, bp, n) 72245223Ssklower char *s, *bp; 72345223Ssklower { 72445223Ssklower static int fd; 72545223Ssklower char buf[BUFSIZ*4]; 72645223Ssklower register char *p1, *p2; 72745223Ssklower 728*45294Ssklower for (p1 = buf; *s; *p1++ = *s++); 72945223Ssklower *p1++ = ':'; 73045223Ssklower *p1++ = ' '; 731*45294Ssklower for (p2=bp; p2 < bp+n; p2++) 732*45294Ssklower if (*p2 >= ' ' && *p2 < 0177) 73345223Ssklower *p1++ = *p2; 73445223Ssklower else { 73545223Ssklower *p1++ = '\\'; 73645223Ssklower *p1++ = ((*p2 & 0300) >> 6) + '0'; 73745223Ssklower *p1++ = ((*p2 & 070) >> 3) + '0'; 73845223Ssklower *p1++ = (*p2 & 07) + '0'; 73945223Ssklower } 74045223Ssklower *p1++ = '\n'; 741*45294Ssklower if (fd <= 0) 74245223Ssklower fd = creat(tracefn, 0666); 74345223Ssklower (void) write(fd, buf, p1-buf); 74445223Ssklower } 745