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;
4745294Ssklower 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
main(argc,argv)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
19945294Ssklower 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*48847Ssklower struct 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 *
lookup(name)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
reapchild()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
fatal(f,msg)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
fatalperror(msg,err)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 */
x29d()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);
36845294Ssklower /*ioctl(pty, TIOCREMECHO, (char *)&on); /* enable special pty mode */
36945294Ssklower /* new equivalent is no processing in pty, no echo, but let
37045294Ssklower user set modes and have either remote end do line mode processing
37145294Ssklower or do it in daemon */
37245294Ssklower ioctl(pty, TIOCEXT, (char *)&on);
37345223Ssklower ioctl(pty, TIOCPKT, (char *)&on);
37445294Ssklower 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);
42345294Ssklower 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 */
43445294Ssklower 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;
43945294Ssklower else if (fcc <= 0)
44045223Ssklower fcc = -1;
44145223Ssklower else {
44245223Ssklower if (tracefn)
44345223Ssklower x29d_trace("netread", fibuf, fcc);
44445294Ssklower 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;
46145294Ssklower else if (pibuf[0] != 0) { /* non-data packet */
46245294Ssklower if (pibuf[0] & TIOCPKT_IOCTL) {
46345294Ssklower if (--pcc > sizeof(pt))
46445294Ssklower pcc = sizeof(pt);
46545294Ssklower old_pt = pt;
46645294Ssklower bcopy(pibuf + 1, (char *)&pt, pcc);
46745223Ssklower pcc = set_x29_parameters();
46845294Ssklower } else
46945223Ssklower pcc = 0;
47045223Ssklower } else /* data packet */
47145223Ssklower pibuf[0] = 0;
47245223Ssklower }
47345223Ssklower
47445223Ssklower if ((obits & (1<<net)) && pcc > 0)
47545294Ssklower if ((cc = write(net, pibuf, pcc)) == pcc) {
47645294Ssklower if (tracefn)
47745223Ssklower x29d_trace("netwrite", pibuf, pcc);
47845223Ssklower pcc = 0;
47945223Ssklower } else {
48045223Ssklower extern char *sys_errlist[];
48145223Ssklower
48245294Ssklower 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) {
49045294Ssklower 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
x25_interrupt()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
cleanup()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
set_x29_parameters()54245223Ssklower set_x29_parameters()
54345223Ssklower {
54445223Ssklower register char *p;
54545294Ssklower int f;
54645294Ssklower char *lim = p + sizeof (pt);
54745223Ssklower
54845223Ssklower if (netp->n_type == X25NET)
54945223Ssklower return (0);
55045294Ssklower if ((old_pt.c_lflag & ICANON) != (pt.c_lflag & ICANON)) {
55145294Ssklower f = pt.c_lflag & ICANON;
55245294Ssklower ioctl(pty, TIOCEXT, &f);
55345294Ssklower /* this precipitates more junk of the same
55445294Ssklower * sort that caused our call here, but we can't
55545294Ssklower * turn it off since something may be going on in our progeny.
55645294Ssklower *
55745294Ssklower * Instead, we'll check the next time around to see if nothing
55845294Ssklower * has changed, and skip informing the network.
55945294Ssklower */
56045294Ssklower }
56145294Ssklower if (bcmp((char *)&pt, (char *)&old_pt, sizeof (pt)) == 0)
56245294Ssklower 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;*/
56745294Ssklower *p++ = X29_ESCAPE_TO_CMD_CODE; *p++ = (pt.c_lflag & ICANON) != 0;
56845223Ssklower
56945294Ssklower *p++ = X29_ECHO_CODE; *p++ = (pt.c_lflag & ECHO) != 0;
57045293Ssklower *p++ = X29_FORWARDING_SIGNAL_CODE;
57145294Ssklower *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;*/
58345294Ssklower *p++ = X29_IDLE_TIMER_CODE; *p++ = (pt.c_lflag & ICANON) ? 0 : 10;
58445293Ssklower
58545293Ssklower /**p++ = X29_AUX_DEV_CONTROL_CODE;*p++ = (f & TANDEM) != 0;*/
58645294Ssklower *p++ = X29_AUX_DEV_CONTROL_CODE;*p++ = (pt.c_iflag & IXOFF) != 0;
58745294Ssklower *p++ = X29_XON_XOFF_CODE; *p++ = (pt.c_iflag & IXON) != 0;
58845294Ssklower if (netp->n_type == CCITT1980) {
58945293Ssklower *p++ = X29_LF_AFTER_CR;
59045293Ssklower /* *p++ = (f & (RAW|CBREAK) || (f & ECHO) == 0) ? 0 : 4; */
59145294Ssklower *p++ = ((pt.c_lflag & (ICANON | ECHO)) != (ICANON | ECHO)) ?
59245293Ssklower 0 : 4;
59345223Ssklower
59445294Ssklower *p++ = X29_EDITING; *p++ = (pt.c_lflag & ICANON) != 0;
59545293Ssklower #define ctlchar(x) \
59645294Ssklower (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 }
60145294Ssklower #undef ctlchar
60245223Ssklower return (p - pibuf);
60345223Ssklower }
60445223Ssklower
60545294Ssklower /* Have to be careful writing to pty. The pad will forward control
60645294Ssklower * characters without necessarily sending an interrupt so if ISIG and
60745294Ssklower * ICANNON are set, must inspect line for quit or interrupt or suspend.
60845294Ssklower */
ptywrite(buf,n)60945294Ssklower ptywrite(buf, n)
61045294Ssklower char *buf;
61145294Ssklower int n;
61245294Ssklower {
61345294Ssklower register char *cp, *lim;
61445294Ssklower char *last;
61545294Ssklower #define is_ctl(x) (pt.c_cc[x] == *(cc_t *)cp)
61645294Ssklower
61745294Ssklower if ((pt.c_lflag & EXTPROC) && (pt.c_lflag & ISIG)) {
61845294Ssklower for (cp = buf, lim = buf + n; cp < lim; cp ++) {
61945294Ssklower if (is_ctl(VLNEXT))
62045294Ssklower { cp++; continue; }
62145294Ssklower if (is_ctl(VSUSP) || is_ctl(VDSUSP) ||
62245294Ssklower is_ctl(VINTR) || is_ctl(VQUIT)) {
62345294Ssklower int onoff = 0;
62445294Ssklower tcflag_t old_echo = pt.c_lflag & ECHO;
62545294Ssklower
62645294Ssklower ioctl(pty, TIOCPKT, (char *)&onoff);
62745294Ssklower ioctl(pty, FIONBIO, (char *)&onoff);
62845294Ssklower ioctl(pty, TIOCEXT, (char *)&onoff);
62945294Ssklower if (old_echo) {
63045294Ssklower pt.c_lflag &= ~ECHO;
63145294Ssklower ioctl(pty, TIOCSETA, (char *)&pt);
63245294Ssklower }
63345294Ssklower n = write(pty, buf, n);
63445294Ssklower onoff = 1;
63545294Ssklower if (old_echo) {
63645294Ssklower pt.c_lflag |= ECHO;
63745294Ssklower ioctl(pty, TIOCSETA, (char *)&pt);
63845294Ssklower }
63945294Ssklower ioctl(pty, TIOCEXT, (char *)&onoff);
64045294Ssklower ioctl(pty, FIONBIO, (char *)&onoff);
64145294Ssklower ioctl(pty, TIOCPKT, (char *)&onoff);
64245294Ssklower return (n);
64345294Ssklower }
64445294Ssklower }
64545294Ssklower }
64645294Ssklower return write(pty, buf, n);
64745294Ssklower }
64845294Ssklower
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
x29_qbit(n)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:
66445294Ssklower for (p = &fibuf[2]; p < fibuf+n; p++) {
66545294Ssklower 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
67145294Ssklower if (*++p >= 0 && *p < sizeof(speeds)) {
67245294Ssklower cfsetspeed(&pt, speeds[*p]);
67345294Ssklower tcsetattr(pty, TCSANOW, &pt);
67445223Ssklower }
67545294Ssklower } 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));
68645294Ssklower 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;
70345294Ssklower for (p2 = "x29d: unknown q-bit packet: "; *p++ = *p2++; );
70445294Ssklower for (p2 = fibuf+1; p2 < fibuf+n; p2++)
70545294Ssklower 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';
71445294Ssklower if (fd <= 0)
71545223Ssklower fd = open(console, 1);
71645223Ssklower (void) write(fd, buf, p-buf);
71745223Ssklower }
71845223Ssklower }
71945223Ssklower }
72045223Ssklower
x29d_trace(s,bp,n)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
72845294Ssklower for (p1 = buf; *s; *p1++ = *s++);
72945223Ssklower *p1++ = ':';
73045223Ssklower *p1++ = ' ';
73145294Ssklower for (p2=bp; p2 < bp+n; p2++)
73245294Ssklower 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';
74145294Ssklower if (fd <= 0)
74245223Ssklower fd = creat(tracefn, 0666);
74345223Ssklower (void) write(fd, buf, p1-buf);
74445223Ssklower }
745