home *** CD-ROM | disk | FTP | other *** search
- /*
- * X.29 server
- *
- * Frank Pronk (...!ubc-vision!pronk)
- * April, September 1984
- *
- * Laboratory for Computational Vision
- * University of British Columbia
- * Copyright (c)
- */
-
- #include <sys/param.h>
- #include <sys/socket.h>
- #include <sys/stat.h>
- #include <sys/wait.h>
-
- #include <netccitt/x25.h>
-
- #include <errno.h>
- #include <netdb.h>
- #include <signal.h>
- #include <sys/ioctl.h>
- #include <sys/termios.h>
- #include <paths.h>
-
- #include "../h/x29.h"
-
- #define BUFSIZ 1024
- #define MAXARGS 10 /* maximum size of server argument list */
-
- #define X25NET 0 /* no ITI parameters */
- #define CCITT1978 1 /* 1978 CCITT standard parameter set */
- #define CCITT1980 2 /* 1980 CCITT standard parameter set */
-
-
- char pibuf[BUFSIZ], fibuf[BUFSIZ];
- int pty, net;
- extern char **environ;
- extern int errno;
- char line[MAXPATHLEN];
- char console[] = "/dev/console";
- short packet_size;
- short debug;
- char *tracefn; /* trace file name */
- char *server;
- short send_banner;
- struct termios pt, old_pt;
- struct sockaddr_x25 sock;
-
- int reapchild();
- struct net *lookup ();
-
- char ccitt1978_prof[] = { /* initial profile */
- Q_BIT, X29_SET_AND_READ_PARMS,
- X29_ECHO_CODE, 1, /* echo on */
- X29_FORWARDING_SIGNAL_CODE, 126, /* forward on all cntl */
- X29_IDLE_TIMER_CODE, 0, /* off */
- X29_AUX_DEV_CONTROL_CODE, 0, /* off */
- X29_RECEIVE_NET_MSGS_CODE, 1, /* xmit network msgs */
- X29_BREAK_PROCEDURE_CODE, 21,
- X29_PADDING_CODE, 0, /* off */
- X29_LINE_FOLDING_CODE, 0, /* off */
- X29_TRANSMISSION_SPEED_CODE, 0,
- X29_XON_XOFF_CODE, 1, /* enable XON/XOFF */
- };
-
- char ccitt1980_prof[] = { /* initial profile */
- Q_BIT, X29_SET_AND_READ_PARMS,
- X29_ECHO_CODE, 1, /* echo on */
- X29_FORWARDING_SIGNAL_CODE, 126, /* forward on all cntl */
- X29_IDLE_TIMER_CODE, 0, /* off */
- X29_AUX_DEV_CONTROL_CODE, 0, /* off */
- X29_RECEIVE_NET_MSGS_CODE, 1, /* xmit network msgs */
- X29_BREAK_PROCEDURE_CODE, 21,
- X29_PADDING_CODE, 0, /* off */
- X29_LINE_FOLDING_CODE, 0, /* off */
- X29_TRANSMISSION_SPEED_CODE, 0,
- X29_XON_XOFF_CODE, 1, /* enable XON/XOFF */
-
- X29_LF_AFTER_CR, 4, /* lf after cr from terminal */
- X29_EDITING, 1, /* on */
- X29_CHARACTER_DELETE, CERASE,
- X29_LINE_DELETE, CKILL,
- X29_LINE_DISPLAY, CRPRNT,
- };
-
- char datapac_prof[] = { /* Canadian X.25 network */
- Q_BIT, X29_SET_AND_READ_PARMS,
- X29_ECHO_CODE, 1, /* echo on */
- X29_FORWARDING_SIGNAL_CODE, 126, /* forward on all cntl */
- X29_IDLE_TIMER_CODE, 0, /* off */
- X29_AUX_DEV_CONTROL_CODE, 0, /* off */
- X29_RECEIVE_NET_MSGS_CODE, 1, /* xmit network msgs */
- X29_BREAK_PROCEDURE_CODE, 21,
- X29_PADDING_CODE, 0, /* off */
- X29_LINE_FOLDING_CODE, 0, /* off */
- X29_TRANSMISSION_SPEED_CODE, 0,
- X29_XON_XOFF_CODE, 1, /* enable XON/XOFF */
-
- X29_LF_AFTER_CR, 4, /* lf after cr from terminal */
- X29_EDITING, 1, /* on */
- X29_CHARACTER_DELETE, CERASE,
- X29_LINE_DELETE, CKILL,
- X29_LINE_DISPLAY, CRPRNT,
-
- /*
- * This rubbish can be removed when Datapac
- * adopts the 1980 standard parameter set.
- */
-
- 0, 0, /* national parameter marker */
- 123, 0, /* parity off */
- };
-
- struct net {
- char *n_name; /* generic name */
- short n_type; /* see defines above */
- char *n_profile; /* initial profile */
- short n_proflen; /* length of n_profile */
- } *netp, nets[] = {
- "x.25", X25NET, 0, 0,
- "1978", CCITT1978, ccitt1978_prof, sizeof(ccitt1978_prof),
- "ccitt1978", CCITT1978, ccitt1978_prof, sizeof(ccitt1978_prof),
- "1980", CCITT1980, ccitt1980_prof, sizeof(ccitt1980_prof),
- "ccitt1980", CCITT1980, ccitt1980_prof, sizeof(ccitt1980_prof),
- "datapac", CCITT1980, datapac_prof, sizeof(datapac_prof),
- 0, 0, 0, 0
- };
-
- main(argc, argv)
- register char **argv;
- {
- register int s, pid;
- register char *p;
-
- /*
- * If this host doesn't support X.25, give up.
- */
- s = socket(AF_CCITT, SOCK_STREAM, 0);
- if (s < 0 && errno == EPROTONOSUPPORT)
- fatal(2, "X.25 is not supported on this machine");
- close(s);
- netp = lookup ("ccitt1978");
- sock.x25_family = AF_CCITT;
- sock.x25_len = sizeof(sock);
- sock.x25_opts.op_flags = X25_MQBIT;
- sock.x25_udata[0] = ITI_CALL;
- sock.x25_udlen = 4;
-
- for (argv++; argc > 1; argc--, argv++)
- if (**argv == '-')
- for (p = *argv+1; *p; p++)
- switch (*p) {
- case 'b':
- send_banner++;
- break;
-
- case 'c':
- if (argc > 1) {
- argc--; argv++;
- if ((netp = lookup (*argv)) == 0)
- fatal(1, "Unknown network type");
- }
- break;
-
- case 'p':
- if (argc > 1) {
- argc--; argv++;
- strcpy (sock.x25_udata, *argv);
- }
- break;
-
- case 'r':
- sock.x25_opts.op_flags |= X25_REVERSE_CHARGE;
- break;
-
- case 'd':
- debug++;
- break;
-
- case 't':
- if (argc > 1) {
- argc--; argv++;
- tracefn = *argv;
- }
- else fatal(1, "missing trace file");
- break;
-
- default:
- fatal (1, "usage: x29d -b -c nettype -p protocol -r -t trace_file server");
- }
- else
- server = *argv;
- if (server == 0)
- fatal (1, "no server specified");
- if (debug == 0)
- daemon(0, 0);
-
- while ((s = socket(AF_CCITT, SOCK_STREAM, 0)) < 0)
- sleep(60);
- while (bind(s, (caddr_t)&sock, sizeof (sock)) < 0)
- sleep(60);
- signal(SIGCHLD, reapchild);
- listen(s, 5);
-
- for (;;) {
- struct sockaddr_x25 from;
- int fromlen = sizeof (from);
-
- if ((net = accept(s, (caddr_t)&from, &fromlen)) < 0) {
- if (errno != EINTR)
- sleep (60);
- continue;
- }
- while ((pid = fork()) < 0)
- sleep(60);
- if (pid == 0) {
- signal(SIGCHLD, SIG_DFL);
- doit(&from);
- }
- close(net);
- }
- /*NOTREACHED*/
- }
-
- struct net *
- lookup (name)
- char *name;
- {
- register struct net *np;
-
- for (np = nets; np->n_name; np++)
- if (strcmp (np->n_name, name) == 0)
- return (np);
- return (0);
- }
-
- reapchild()
- {
- union wait status;
-
- while (wait3(&status, WNOHANG, 0) > 0)
- ;
- }
-
- char *envinit[] = { "TERM=ccitt", 0 };
- int cleanup();
- struct termios term;
-
- /*
- * Get a pty, scan input lines.
- */
- doit(who)
- struct sockaddr_x25 *who;
- {
- register char *cp;
- int i, p, t;
-
- packet_size = 1 << who->x25_opts.op_psize;
- i = forkpty(&pty, line, &term, 0);
- if (i > 0)
- x29d();
- if (i < 0)
- fatalperror("fork", errno);
- environ = envinit;
- call_server (who);
- /*NOTREACHED*/
- }
-
- call_server (who)
- struct sockaddr_x25 *who;
- {
- register struct hostent *hp = 0;
- register char *p, **ap;
- char *args[MAXARGS];
- struct stat st;
- struct hostent *getx25hostbyaddr();
- int ccitt = 0;
-
- p = server;
- while (*p && *p != ' ' && *p != '\t') /* split program from args */
- p++;
- if (*p)
- *p++ = '\0';
- ap = args;
- while (*p) {
- while (*p == ' ' || *p == '\t')
- p++;
- if (ap < &args[MAXARGS-2])
- *ap++ = p;
- if (strcmp(p, "-ccitt") == 0)
- ccitt = 1;
- while (*p && *p != ' ' && *p != '\t')
- p++;
- if (*p)
- *p++ = '\0';
- }
- if (stat (server, &st) < 0)
- fatalperror (server, errno);
- /*
- * For security: if running as root, switch to user
- * and group id of server. This prevents privately
- * maintainted or bogus servers from getting super-
- * user permissions.
- */
- if (getuid() == 0) {
- setgid (st.st_gid);
- setuid (st.st_uid);
- }
- if (hp = getx25hostbyaddr (who->x25_addr))
- *ap++ = hp->h_name;
- else
- *ap++ = (char *)who->x25_addr;
- /*
- * If the -ccitt flag was given, add another argument
- * to tell login if charging is being reversed or not.
- */
- if (ccitt)
- *ap++ = (who->x25_opts.op_flags & X25_REVERSE_CHARGE) ? "y" : "n";
- *ap = 0;
- execv (server, args);
- fatalperror (server, errno);
- /*NOTREACHED*/
- }
-
- fatal(f, msg)
- int f;
- char *msg;
- {
- register char *p;
- char buf[BUFSIZ], *index();
-
- p = buf;
- if (f == net)
- *p++ = 0;
- strcpy(p, "x29d: ");
- strcat(p, msg);
- strcat(p, "\n");
- (void) write(f, p, (index(p, '\n')-p)+1);
- exit(1);
- }
-
- fatalperror(msg, err)
- char *msg;
- {
- char buf[BUFSIZ];
- extern char *sys_errlist[];
-
- strcpy(buf, msg);
- strcat(buf, ": ");
- strcat(buf, sys_errlist[err]);
- fatal(net, buf);
- }
-
- /*
- * Main loop. Select from pty and network, and
- * hand data to iti receiver.
- */
- x29d()
- {
- register int pcc, fcc, cc;
- register char *fbp;
- int pgrp, x25_interrupt(), on = 1;
- char hostname[32];
-
- ioctl(net, FIONBIO, (char *)&on);
- ioctl(pty, FIONBIO, (char *)&on);
- /*ioctl(pty, TIOCREMECHO, (char *)&on); /* enable special pty mode */
- /* new equivalent is no processing in pty, no echo, but let
- user set modes and have either remote end do line mode processing
- or do it in daemon */
- ioctl(pty, TIOCEXT, (char *)&on);
- ioctl(pty, TIOCPKT, (char *)&on);
- ioctl(pty, TIOCGETA, (char *)&pt);
- signal(SIGPIPE, SIG_IGN); /* why not cleanup? --kwl */
- signal(SIGTSTP, SIG_IGN);
- signal(SIGCHLD, cleanup);
- signal(SIGHUP, cleanup);
-
- signal(SIGTTOU, SIG_IGN);
- signal(SIGURG, x25_interrupt); /* for out-of-band data */
-
- if (netp->n_proflen)
- (void) write(net, netp->n_profile, netp->n_proflen);
-
- /*
- * Show banner that getty never gave.
- */
- if (send_banner) {
- gethostname(hostname, sizeof (hostname));
- #ifdef BSD4_3
- strcpy(pibuf+1, "\r\n\r\n4.3 BSD UNIX (");
- #else
- strcpy(pibuf+1, "\r\n\r\n4.2 BSD UNIX (");
- #endif
- strcat(pibuf+1, hostname);
- strcat(pibuf+1, ")\r\n\r\n");
- pcc = strlen(pibuf+1) + 1;
- } else
- pcc = 0;
-
- fcc = 0;
- for (;;) {
- int ibits, obits;
-
- ibits = obits = 0;
- /*
- * Never look for input if there's still
- * stuff in the corresponding output buffer
- */
- if (fcc >= 0) /* net connection alive? */
- if (fcc && pcc >= 0) /* output pending? */
- obits |= (1 << pty);
- else
- if (pcc >= 0) /* pty still alive? */
- ibits |= (1 << net);
- if (pcc >= 0) /* pty connection alive? */
- if (pcc && fcc >= 0) /* output pending? */
- obits |= (1 << net);
- else
- if (fcc >= 0) /* net still alive? */
- ibits |= (1 << pty);
- if (ibits == 0 && obits == 0)
- break;
- (void) select(16, &ibits, &obits, (int *)0, 0);
- if (ibits == 0 && obits == 0) {
- sleep(5);
- continue;
- }
-
- /*
- * Something to read from the network...
- */
- if (fcc == 0 && (ibits & (1 << net))) {
- fcc = read(net, fibuf, BUFSIZ);
- fbp = fibuf+1;
- if (fcc < 0 && errno == EWOULDBLOCK)
- fcc = 0;
- else if (fcc <= 0)
- fcc = -1;
- else {
- if (tracefn)
- x29d_trace("netread", fibuf, fcc);
- if (fibuf[0] & Q_BIT) {
- x29_qbit(fcc);
- fcc = 0;
- } else
- fcc--;
- }
- }
-
- /*
- * Something to read from the pty...
- */
- if (ibits & (1 << pty)) {
- pcc = read(pty, pibuf, packet_size+1);
- if (pcc < 0 && errno == EWOULDBLOCK)
- pcc = 0;
- else if (pcc <= 0)
- pcc = -1;
- else if (pibuf[0] != 0) { /* non-data packet */
- if (pibuf[0] & TIOCPKT_IOCTL) {
- if (--pcc > sizeof(pt))
- pcc = sizeof(pt);
- old_pt = pt;
- bcopy(pibuf + 1, (char *)&pt, pcc);
- pcc = set_x29_parameters();
- } else
- pcc = 0;
- } else /* data packet */
- pibuf[0] = 0;
- }
-
- if ((obits & (1<<net)) && pcc > 0)
- if ((cc = write(net, pibuf, pcc)) == pcc) {
- if (tracefn)
- x29d_trace("netwrite", pibuf, pcc);
- pcc = 0;
- } else {
- extern char *sys_errlist[];
-
- if (tracefn)
- x29d_trace("netwrite",
- sys_errlist[errno],
- strlen(sys_errlist[errno]));
-
- }
-
- if ((obits & (1 << pty)) && fcc > 0) {
- cc = ptywrite(fbp, fcc);
- if (cc > 0) {
- fcc -= cc;
- fbp += cc;
- }
- }
- }
- cleanup();
- }
-
-
- /*
- * Send interrupt to process on other side of pty.
- * If it is in raw mode, just write NULL;
- * otherwise, write intr char.
- */
-
- x25_interrupt()
- {
- struct termios tt;
- int zero = 0;
-
- signal(SIGURG, x25_interrupt);
- tcgetattr(pty, &tt);
- if (tt.c_lflag & ISIG) {
- tcsetattr(pty, TCSAFLUSH, &tt);
- (void) write(pty, &tt.c_cc[VINTR], 1);
- } else
- (void) write(pty, "\0", 1);
- }
-
- cleanup()
- {
- char *p;
-
- p = line + sizeof(_PATH_DEV) - 1;
- if (logout(p))
- logwtmp(p, "", "");
- (void)chmod(line, 0666);
- (void)chown(line, 0, 0);
- *p = 'p';
- (void)chmod(line, 0666);
- (void)chown(line, 0, 0);
- shutdown(net, 2);
- exit(1);
- }
-
- /*
- * Map unix tty modes and special characters
- * into x29 parameters.
- */
-
- set_x29_parameters()
- {
- register char *p;
- int f;
- char *lim = p + sizeof (pt);
-
- if (netp->n_type == X25NET)
- return (0);
- if ((old_pt.c_lflag & ICANON) != (pt.c_lflag & ICANON)) {
- f = pt.c_lflag & ICANON;
- ioctl(pty, TIOCEXT, &f);
- /* this precipitates more junk of the same
- * sort that caused our call here, but we can't
- * turn it off since something may be going on in our progeny.
- *
- * Instead, we'll check the next time around to see if nothing
- * has changed, and skip informing the network.
- */
- }
- if (bcmp((char *)&pt, (char *)&old_pt, sizeof (pt)) == 0)
- return;
- p = pibuf;
- *p++ = Q_BIT;
- *p++ = X29_SET_PARMS;
- /* *p++ = X29_ESCAPE_TO_CMD_CODE; *p++ = (f & (RAW|CBREAK)) == 0;*/
- *p++ = X29_ESCAPE_TO_CMD_CODE; *p++ = (pt.c_lflag & ICANON) != 0;
-
- *p++ = X29_ECHO_CODE; *p++ = (pt.c_lflag & ECHO) != 0;
- *p++ = X29_FORWARDING_SIGNAL_CODE;
- *p++ = (pt.c_lflag & ISIG) ? 0 : 126;
-
- /*
- * The value of 10 (0.5 seconds) for the idle timer when
- * in raw or cbreak mode is a compromise value. For good
- * interactive response this value should be as low as
- * possible; for reasonable efficiency with file transfers
- * this value should be at fairly high. This number should
- * be changed to suit local requirements.
- */
-
- /**p++ = X29_IDLE_TIMER_CODE; *p++ = (f & (RAW|CBREAK)) ? 10 : 0;*/
- *p++ = X29_IDLE_TIMER_CODE; *p++ = (pt.c_lflag & ICANON) ? 0 : 10;
-
- /**p++ = X29_AUX_DEV_CONTROL_CODE;*p++ = (f & TANDEM) != 0;*/
- *p++ = X29_AUX_DEV_CONTROL_CODE;*p++ = (pt.c_iflag & IXOFF) != 0;
- *p++ = X29_XON_XOFF_CODE; *p++ = (pt.c_iflag & IXON) != 0;
- if (netp->n_type == CCITT1980) {
- *p++ = X29_LF_AFTER_CR;
- /* *p++ = (f & (RAW|CBREAK) || (f & ECHO) == 0) ? 0 : 4; */
- *p++ = ((pt.c_lflag & (ICANON | ECHO)) != (ICANON | ECHO)) ?
- 0 : 4;
-
- *p++ = X29_EDITING; *p++ = (pt.c_lflag & ICANON) != 0;
- #define ctlchar(x) \
- (0 == (pt.c_lflag & ICANON) || pt.c_cc[x] == _POSIX_VDISABLE) ? 0 : pt.c_cc[x]
- *p++ = X29_CHARACTER_DELETE; *p++ = ctlchar(VERASE);
- *p++ = X29_LINE_DELETE; *p++ = ctlchar(VKILL);
- *p++ = X29_LINE_DISPLAY; *p++ = ctlchar(VREPRINT);
- }
- #undef ctlchar
- return (p - pibuf);
- }
-
- /* Have to be careful writing to pty. The pad will forward control
- * characters without necessarily sending an interrupt so if ISIG and
- * ICANNON are set, must inspect line for quit or interrupt or suspend.
- */
- ptywrite(buf, n)
- char *buf;
- int n;
- {
- register char *cp, *lim;
- char *last;
- #define is_ctl(x) (pt.c_cc[x] == *(cc_t *)cp)
-
- if ((pt.c_lflag & EXTPROC) && (pt.c_lflag & ISIG)) {
- for (cp = buf, lim = buf + n; cp < lim; cp ++) {
- if (is_ctl(VLNEXT))
- { cp++; continue; }
- if (is_ctl(VSUSP) || is_ctl(VDSUSP) ||
- is_ctl(VINTR) || is_ctl(VQUIT)) {
- int onoff = 0;
- tcflag_t old_echo = pt.c_lflag & ECHO;
-
- ioctl(pty, TIOCPKT, (char *)&onoff);
- ioctl(pty, FIONBIO, (char *)&onoff);
- ioctl(pty, TIOCEXT, (char *)&onoff);
- if (old_echo) {
- pt.c_lflag &= ~ECHO;
- ioctl(pty, TIOCSETA, (char *)&pt);
- }
- n = write(pty, buf, n);
- onoff = 1;
- if (old_echo) {
- pt.c_lflag |= ECHO;
- ioctl(pty, TIOCSETA, (char *)&pt);
- }
- ioctl(pty, TIOCEXT, (char *)&onoff);
- ioctl(pty, FIONBIO, (char *)&onoff);
- ioctl(pty, TIOCPKT, (char *)&onoff);
- return (n);
- }
- }
- }
- return write(pty, buf, n);
- }
-
- /*
- * Process Q BIT (control) packets from the net.
- * The only message that we are interested in are
- * those indicating output is being discarded.
- */
-
- x29_qbit(n)
- {
- register char *p;
-
- switch (fibuf[1]) {
- case X29_SET_PARMS:
- case X29_SET_AND_READ_PARMS:
- case X29_PARAMETER_INDICATION:
- case X29_INDICATION_OF_BREAK:
- for (p = &fibuf[2]; p < fibuf+n; p++) {
- if (*p == X29_TRANSMISSION_SPEED_CODE) {
- static char speeds[] = {
- B110, B0, B300, B1200, B600,
- B0, B0, B0, B0, B0, B0, B0,
- B2400, B4800, B9600, EXTA };
-
- if (*++p >= 0 && *p < sizeof(speeds)) {
- cfsetspeed(&pt, speeds[*p]);
- tcsetattr(pty, TCSANOW, &pt);
- }
- } else if (*p == X29_DISCARD_OUTPUT_CODE && *++p != 0) {
- char message[4];
-
- /*
- * Always re-enable normal output
- */
- message[0] = Q_BIT;
- message[1] = X29_SET_PARMS;
- message[2] = X29_DISCARD_OUTPUT_CODE;
- message[3] = 0;
- (void) write(net, message, sizeof(message));
- if (tracefn)
- x29d_trace("netwrite", message, 4);
- }
- }
- return;
-
- default: {
- register char *p2;
- char buf[BUFSIZ*4];
- static int fd;
-
- /*
- * Bad news - we received an x29 error message or
- * some other unknown packet. Dump the contents
- * of the packet on the console.
- */
- p = buf;
- for (p2 = "x29d: unknown q-bit packet: "; *p++ = *p2++; );
- for (p2 = fibuf+1; p2 < fibuf+n; p2++)
- if (*p2 >= ' ' && *p2 < 0177)
- *p++ = *p2;
- else {
- *p++ = '\\';
- *p++ = ((*p2 & 0300) >> 6) + '0';
- *p++ = ((*p2 & 070) >> 3) + '0';
- *p++ = (*p2 & 07) + '0';
- }
- *p++ = '\n';
- if (fd <= 0)
- fd = open(console, 1);
- (void) write(fd, buf, p-buf);
- }
- }
- }
-
- x29d_trace(s, bp, n)
- char *s, *bp;
- {
- static int fd;
- char buf[BUFSIZ*4];
- register char *p1, *p2;
-
- for (p1 = buf; *s; *p1++ = *s++);
- *p1++ = ':';
- *p1++ = ' ';
- for (p2=bp; p2 < bp+n; p2++)
- if (*p2 >= ' ' && *p2 < 0177)
- *p1++ = *p2;
- else {
- *p1++ = '\\';
- *p1++ = ((*p2 & 0300) >> 6) + '0';
- *p1++ = ((*p2 & 070) >> 3) + '0';
- *p1++ = (*p2 & 07) + '0';
- }
- *p1++ = '\n';
- if (fd <= 0)
- fd = creat(tracefn, 0666);
- (void) write(fd, buf, p1-buf);
- }
-