xref: /csrg-svn/contrib/usr.x25/x29d/x29d.c (revision 45223)
1*45223Ssklower /*
2*45223Ssklower  * X.29 server
3*45223Ssklower  *
4*45223Ssklower  * Frank Pronk (...!ubc-vision!pronk)
5*45223Ssklower  * April, September 1984
6*45223Ssklower  *
7*45223Ssklower  * Laboratory for Computational Vision
8*45223Ssklower  * University of British Columbia
9*45223Ssklower  * Copyright (c)
10*45223Ssklower  */
11*45223Ssklower 
12*45223Ssklower #include <sys/param.h>
13*45223Ssklower #include <sys/socket.h>
14*45223Ssklower #include <sys/stat.h>
15*45223Ssklower #include <sys/wait.h>
16*45223Ssklower 
17*45223Ssklower #include <netccitt/x25.h>
18*45223Ssklower 
19*45223Ssklower #include <errno.h>
20*45223Ssklower #include <netdb.h>
21*45223Ssklower #include <sgtty.h>
22*45223Ssklower #include <signal.h>
23*45223Ssklower 
24*45223Ssklower #include "../h/x29.h"
25*45223Ssklower 
26*45223Ssklower #define BUFSIZ		1024
27*45223Ssklower #define MAXARGS		10	/* maximum size of server argument list */
28*45223Ssklower 
29*45223Ssklower #define X25NET		0	/* no ITI parameters */
30*45223Ssklower #define CCITT1978	1	/* 1978 CCITT standard parameter set */
31*45223Ssklower #define CCITT1980	2	/* 1980 CCITT standard parameter set */
32*45223Ssklower 
33*45223Ssklower 
34*45223Ssklower char	pibuf[BUFSIZ], fibuf[BUFSIZ];
35*45223Ssklower int	pty, net;
36*45223Ssklower extern	char **environ;
37*45223Ssklower extern	int errno;
38*45223Ssklower char	line[sizeof("/dev/ptyp0")];
39*45223Ssklower char	console[] = "/dev/console";
40*45223Ssklower short	packet_size;
41*45223Ssklower char	*tracefn;		/* trace file name */
42*45223Ssklower char	*server;
43*45223Ssklower short	send_banner;
44*45223Ssklower struct	sockaddr_x25 sock;
45*45223Ssklower 
46*45223Ssklower int	reapchild();
47*45223Ssklower struct	net *lookup ();
48*45223Ssklower 
49*45223Ssklower char	ccitt1978_prof[] = {		/* initial profile */
50*45223Ssklower 	Q_BIT,	X29_SET_AND_READ_PARMS,
51*45223Ssklower 	X29_ECHO_CODE,			1,	/* echo on */
52*45223Ssklower 	X29_FORWARDING_SIGNAL_CODE,	126,	/* forward on all cntl */
53*45223Ssklower 	X29_IDLE_TIMER_CODE,		0,	/* off */
54*45223Ssklower 	X29_AUX_DEV_CONTROL_CODE,	0,	/* off */
55*45223Ssklower 	X29_RECEIVE_NET_MSGS_CODE,	1,	/* xmit network msgs */
56*45223Ssklower 	X29_BREAK_PROCEDURE_CODE,	21,
57*45223Ssklower 	X29_PADDING_CODE,		0,	/* off */
58*45223Ssklower 	X29_LINE_FOLDING_CODE,		0,	/* off */
59*45223Ssklower 	X29_TRANSMISSION_SPEED_CODE,	0,
60*45223Ssklower 	X29_XON_XOFF_CODE,		1,	/* enable XON/XOFF */
61*45223Ssklower };
62*45223Ssklower 
63*45223Ssklower char	ccitt1980_prof[] = {		/* initial profile */
64*45223Ssklower 	Q_BIT,	X29_SET_AND_READ_PARMS,
65*45223Ssklower 	X29_ECHO_CODE,			1,	/* echo on */
66*45223Ssklower 	X29_FORWARDING_SIGNAL_CODE,	126,	/* forward on all cntl */
67*45223Ssklower 	X29_IDLE_TIMER_CODE,		0,	/* off */
68*45223Ssklower 	X29_AUX_DEV_CONTROL_CODE,	0,	/* off */
69*45223Ssklower 	X29_RECEIVE_NET_MSGS_CODE,	1,	/* xmit network msgs */
70*45223Ssklower 	X29_BREAK_PROCEDURE_CODE,	21,
71*45223Ssklower 	X29_PADDING_CODE,		0,	/* off */
72*45223Ssklower 	X29_LINE_FOLDING_CODE,		0,	/* off */
73*45223Ssklower 	X29_TRANSMISSION_SPEED_CODE,	0,
74*45223Ssklower 	X29_XON_XOFF_CODE,		1,	/* enable XON/XOFF */
75*45223Ssklower 
76*45223Ssklower 	X29_LF_AFTER_CR,		4,	/* lf after cr from terminal */
77*45223Ssklower 	X29_EDITING,			1,	/* on */
78*45223Ssklower 	X29_CHARACTER_DELETE,		CERASE,
79*45223Ssklower 	X29_LINE_DELETE,		CKILL,
80*45223Ssklower 	X29_LINE_DISPLAY,		CRPRNT,
81*45223Ssklower };
82*45223Ssklower 
83*45223Ssklower char	datapac_prof[] = {		/* Canadian X.25 network */
84*45223Ssklower 	Q_BIT,	X29_SET_AND_READ_PARMS,
85*45223Ssklower 	X29_ECHO_CODE,			1,	/* echo on */
86*45223Ssklower 	X29_FORWARDING_SIGNAL_CODE,	126,	/* forward on all cntl */
87*45223Ssklower 	X29_IDLE_TIMER_CODE,		0,	/* off */
88*45223Ssklower 	X29_AUX_DEV_CONTROL_CODE,	0,	/* off */
89*45223Ssklower 	X29_RECEIVE_NET_MSGS_CODE,	1,	/* xmit network msgs */
90*45223Ssklower 	X29_BREAK_PROCEDURE_CODE,	21,
91*45223Ssklower 	X29_PADDING_CODE,		0,	/* off */
92*45223Ssklower 	X29_LINE_FOLDING_CODE,		0,	/* off */
93*45223Ssklower 	X29_TRANSMISSION_SPEED_CODE,	0,
94*45223Ssklower 	X29_XON_XOFF_CODE,		1,	/* enable XON/XOFF */
95*45223Ssklower 
96*45223Ssklower 	X29_LF_AFTER_CR,		4,	/* lf after cr from terminal */
97*45223Ssklower 	X29_EDITING,			1,	/* on */
98*45223Ssklower 	X29_CHARACTER_DELETE,		CERASE,
99*45223Ssklower 	X29_LINE_DELETE,		CKILL,
100*45223Ssklower 	X29_LINE_DISPLAY,		CRPRNT,
101*45223Ssklower 
102*45223Ssklower 	/*
103*45223Ssklower 	 * This rubbish can be removed when Datapac
104*45223Ssklower 	 * adopts the 1980 standard parameter set.
105*45223Ssklower 	 */
106*45223Ssklower 
107*45223Ssklower 	0,				0,	/* national parameter marker */
108*45223Ssklower 	123,				0,	/* parity off */
109*45223Ssklower };
110*45223Ssklower 
111*45223Ssklower struct	net {
112*45223Ssklower 	char	*n_name;	/* generic name */
113*45223Ssklower 	short	n_type;		/* see defines above */
114*45223Ssklower 	char	*n_profile;	/* initial profile */
115*45223Ssklower 	short	n_proflen;	/* length of n_profile */
116*45223Ssklower } *netp, nets[] = {
117*45223Ssklower 	"x.25",		X25NET,		0,		0,
118*45223Ssklower 	"1978",		CCITT1978,	ccitt1978_prof,	sizeof(ccitt1978_prof),
119*45223Ssklower 	"ccitt1978",	CCITT1978,	ccitt1978_prof,	sizeof(ccitt1978_prof),
120*45223Ssklower 	"1980",		CCITT1980,	ccitt1980_prof,	sizeof(ccitt1980_prof),
121*45223Ssklower 	"ccitt1980",	CCITT1980,	ccitt1980_prof,	sizeof(ccitt1980_prof),
122*45223Ssklower 	"datapac",	CCITT1980,	datapac_prof,	sizeof(datapac_prof),
123*45223Ssklower 	0,		0,		0,		0
124*45223Ssklower };
125*45223Ssklower 
126*45223Ssklower main(argc, argv)
127*45223Ssklower register char **argv;
128*45223Ssklower {
129*45223Ssklower 	register int s, pid;
130*45223Ssklower 	register char *p;
131*45223Ssklower 
132*45223Ssklower #ifdef waterloo
133*45223Ssklower 	/*
134*45223Ssklower 	 * If this host doesn't support X.25, give up.
135*45223Ssklower 	 */
136*45223Ssklower 	s = socket(AF_CCITT, SOCK_STREAM, 0);
137*45223Ssklower 	if (s < 0 && errno == EPROTONOSUPPORT)
138*45223Ssklower 		fatal(2, "X.25 is not supported on this machine");
139*45223Ssklower 	close(s);
140*45223Ssklower #endif
141*45223Ssklower 	netp = lookup ("ccitt1978");
142*45223Ssklower 	sock.x25_family = AF_CCITT;
143*45223Ssklower 	sock.x25_opts.op_flags = X25_MQBIT;
144*45223Ssklower 	sock.x25_udata[0] = ITI_CALL;
145*45223Ssklower 	sock.x25_udlen = 4;
146*45223Ssklower 
147*45223Ssklower 	for (argv++; argc > 1; argc--, argv++)
148*45223Ssklower 		if (**argv == '-')
149*45223Ssklower 			for (p = *argv+1; *p; p++)
150*45223Ssklower 			switch (*p) {
151*45223Ssklower 			case 'b':
152*45223Ssklower 				send_banner++;
153*45223Ssklower 				break;
154*45223Ssklower 
155*45223Ssklower 			case 'c':
156*45223Ssklower 				if (argc > 1) {
157*45223Ssklower 					argc--; argv++;
158*45223Ssklower 					if ((netp = lookup (*argv)) == 0)
159*45223Ssklower 						fatal(1, "Unknown network type");
160*45223Ssklower 				}
161*45223Ssklower 				break;
162*45223Ssklower 
163*45223Ssklower 			case 'p':
164*45223Ssklower 				if (argc > 1) {
165*45223Ssklower 					argc--; argv++;
166*45223Ssklower 					strcpy (sock.x25_udata, *argv);
167*45223Ssklower 				}
168*45223Ssklower 				break;
169*45223Ssklower 
170*45223Ssklower 			case 'r':
171*45223Ssklower 				sock.x25_opts.op_flags |= X25_REVERSE_CHARGE;
172*45223Ssklower 				break;
173*45223Ssklower 
174*45223Ssklower 			case 't':
175*45223Ssklower 				if (argc > 1) {
176*45223Ssklower 					argc--; argv++;
177*45223Ssklower 					tracefn = *argv;
178*45223Ssklower 				}
179*45223Ssklower 				else fatal(1, "missing trace file");
180*45223Ssklower 				break;
181*45223Ssklower 
182*45223Ssklower 			default:
183*45223Ssklower 				fatal (1, "usage: x29d -b -c nettype -p protocol -r -t trace_file server");
184*45223Ssklower 			}
185*45223Ssklower 		else
186*45223Ssklower 			server = *argv;
187*45223Ssklower 	if (server == 0)
188*45223Ssklower 		fatal (1, "no server specified");
189*45223Ssklower 	if (fork())
190*45223Ssklower 		exit(0);
191*45223Ssklower 	for (s = 0; s < 10; s++)
192*45223Ssklower 		(void) close(s);
193*45223Ssklower 	(void) open("/", 0);
194*45223Ssklower 	(void) dup2(0, 1);
195*45223Ssklower 	(void) dup2(0, 2);
196*45223Ssklower 	{ int tt = open("/dev/tty", 2);
197*45223Ssklower 	  if (tt > 0) {
198*45223Ssklower 		ioctl(tt, TIOCNOTTY, (char *)0);
199*45223Ssklower 		close(tt);
200*45223Ssklower 	  }
201*45223Ssklower 	}
202*45223Ssklower 
203*45223Ssklower 	while((s = socket(AF_CCITT, SOCK_STREAM, 0)) < 0)
204*45223Ssklower 		sleep(60);
205*45223Ssklower 	while (bind(s, (caddr_t)&sock, sizeof (sock)) < 0)
206*45223Ssklower 		sleep(60);
207*45223Ssklower 	signal(SIGCHLD, reapchild);
208*45223Ssklower 	listen(s, 5);
209*45223Ssklower 
210*45223Ssklower 	for (;;) {
211*45223Ssklower 		struct sockaddr_x25 from;
212*45223Ssklower 		int fromlen = sizeof (from);
213*45223Ssklower 
214*45223Ssklower 		if ((net = accept(s, (caddr_t)&from, &fromlen)) < 0) {
215*45223Ssklower 			if (errno != EINTR)
216*45223Ssklower 				sleep (60);
217*45223Ssklower 			continue;
218*45223Ssklower 		}
219*45223Ssklower 		while ((pid = fork()) < 0)
220*45223Ssklower 			sleep(60);
221*45223Ssklower 		if (pid == 0) {
222*45223Ssklower 			signal(SIGCHLD, SIG_DFL);
223*45223Ssklower 			doit(&from);
224*45223Ssklower 		}
225*45223Ssklower 		close(net);
226*45223Ssklower 	}
227*45223Ssklower 	/*NOTREACHED*/
228*45223Ssklower }
229*45223Ssklower 
230*45223Ssklower struct net *
231*45223Ssklower lookup (name)
232*45223Ssklower char *name;
233*45223Ssklower {
234*45223Ssklower 	register struct net *np;
235*45223Ssklower 
236*45223Ssklower 	for (np = nets; np->n_name; np++)
237*45223Ssklower 		if (strcmp (np->n_name, name) == 0)
238*45223Ssklower 			return (np);
239*45223Ssklower 	return (0);
240*45223Ssklower }
241*45223Ssklower 
242*45223Ssklower reapchild()
243*45223Ssklower {
244*45223Ssklower 	union wait status;
245*45223Ssklower 
246*45223Ssklower 	while (wait3(&status, WNOHANG, 0) > 0)
247*45223Ssklower 		;
248*45223Ssklower }
249*45223Ssklower 
250*45223Ssklower char	*envinit[] = { "TERM=ccitt", 0 };
251*45223Ssklower int	cleanup();
252*45223Ssklower 
253*45223Ssklower /*
254*45223Ssklower  * Get a pty, scan input lines.
255*45223Ssklower  */
256*45223Ssklower doit(who)
257*45223Ssklower struct sockaddr_x25 *who;
258*45223Ssklower {
259*45223Ssklower 	register char *cp;
260*45223Ssklower 	register int i, p, t;
261*45223Ssklower 	struct sgttyb b;
262*45223Ssklower 	struct stat sb;
263*45223Ssklower 
264*45223Ssklower 	strcpy(line, "/dev/ptyp0");
265*45223Ssklower 	cp = line;
266*45223Ssklower 	for (t = 'p'; ; t++) {
267*45223Ssklower 		cp[strlen("/dev/pty")] = t;
268*45223Ssklower 		if (stat(line, &sb) < 0)
269*45223Ssklower 			break;
270*45223Ssklower 		for (i = 0; i < 16; i++) {
271*45223Ssklower 			cp[strlen("/dev/ptyp")] = "0123456789abcdef"[i];
272*45223Ssklower 			p = open(cp, 2);
273*45223Ssklower 			if (p > 0)
274*45223Ssklower 				goto gotpty;
275*45223Ssklower 		}
276*45223Ssklower 	}
277*45223Ssklower 	fatal(net, "All pty ports in use");
278*45223Ssklower 	/*NOTREACHED*/
279*45223Ssklower gotpty:
280*45223Ssklower 	pty = p;
281*45223Ssklower 	(void) dup2(net, 0);
282*45223Ssklower 	cp[strlen("/dev/")] = 't';
283*45223Ssklower 	t = open("/dev/tty", 2);
284*45223Ssklower 	if (t >= 0) {
285*45223Ssklower 		ioctl(t, TIOCNOTTY, (char *)0);
286*45223Ssklower 		close(t);
287*45223Ssklower 	}
288*45223Ssklower 	t = open(cp, 2);	/* slave side of pty */
289*45223Ssklower 	if (t < 0)
290*45223Ssklower 		fatalperror(cp, errno);
291*45223Ssklower 	ioctl(t, TIOCGETP, (char *)&b);
292*45223Ssklower 	b.sg_flags = CRMOD|XTABS|ANYP|ECHO;
293*45223Ssklower 	ioctl(t, TIOCSETP, &b);
294*45223Ssklower 	packet_size = 1 << who->x25_opts.op_psize;
295*45223Ssklower 	if ((i = fork()) < 0)
296*45223Ssklower 		fatalperror("fork", errno);
297*45223Ssklower 	if (i)
298*45223Ssklower 		x29d();
299*45223Ssklower 	close(net);
300*45223Ssklower 	close(p);
301*45223Ssklower 	(void) dup2(t, 0);
302*45223Ssklower 	(void) dup2(t, 1);
303*45223Ssklower 	(void) dup2(t, 2);
304*45223Ssklower 	close(t);
305*45223Ssklower 	environ = envinit;
306*45223Ssklower 	call_server (who);
307*45223Ssklower 	/*NOTREACHED*/
308*45223Ssklower }
309*45223Ssklower 
310*45223Ssklower call_server (who)
311*45223Ssklower struct sockaddr_x25 *who;
312*45223Ssklower {
313*45223Ssklower 	register struct hostent *hp = 0;
314*45223Ssklower 	register char *p, **ap;
315*45223Ssklower 	char *args[MAXARGS];
316*45223Ssklower 	struct stat st;
317*45223Ssklower 	struct hostent *getx25hostbyaddr();
318*45223Ssklower 	int ccitt = 0;
319*45223Ssklower 
320*45223Ssklower 	p = server;
321*45223Ssklower 	while (*p && *p != ' ' && *p != '\t')	/* split program from args */
322*45223Ssklower 		p++;
323*45223Ssklower 	if (*p)
324*45223Ssklower 		*p++ = '\0';
325*45223Ssklower 	ap = args;
326*45223Ssklower 	while (*p) {
327*45223Ssklower 		while (*p == ' ' || *p == '\t')
328*45223Ssklower 			p++;
329*45223Ssklower 		if (ap < &args[MAXARGS-2])
330*45223Ssklower 			*ap++ = p;
331*45223Ssklower 		if (strcmp(p, "-ccitt") == 0)
332*45223Ssklower 			ccitt = 1;
333*45223Ssklower 		while (*p && *p != ' ' && *p != '\t')
334*45223Ssklower 			p++;
335*45223Ssklower 		if (*p)
336*45223Ssklower 			*p++ = '\0';
337*45223Ssklower 	}
338*45223Ssklower 	if (stat (server, &st) < 0)
339*45223Ssklower 		fatalperror (server, errno);
340*45223Ssklower 	/*
341*45223Ssklower 	 * For security: if running as root, switch to user
342*45223Ssklower 	 * and group id of server.  This prevents privately
343*45223Ssklower 	 * maintainted or bogus servers from getting super-
344*45223Ssklower 	 * user permissions.
345*45223Ssklower 	 */
346*45223Ssklower 	if (getuid() == 0) {
347*45223Ssklower 		setgid (st.st_gid);
348*45223Ssklower 		setuid (st.st_uid);
349*45223Ssklower 	}
350*45223Ssklower 	if (hp = getx25hostbyaddr (who->x25_addr))
351*45223Ssklower 		*ap++ = hp->h_name;
352*45223Ssklower 	else
353*45223Ssklower 		*ap++ = (char *)who->x25_addr;
354*45223Ssklower 	/*
355*45223Ssklower 	 * If the -ccitt flag was given, add another argument
356*45223Ssklower 	 * to tell login if charging is being reversed or not.
357*45223Ssklower 	 */
358*45223Ssklower 	if (ccitt)
359*45223Ssklower 		*ap++ = (who->x25_opts.op_flags & X25_REVERSE_CHARGE) ? "y" : "n";
360*45223Ssklower 	*ap = 0;
361*45223Ssklower 	execv (server, args);
362*45223Ssklower 	fatalperror (server, errno);
363*45223Ssklower 	/*NOTREACHED*/
364*45223Ssklower }
365*45223Ssklower 
366*45223Ssklower fatal(f, msg)
367*45223Ssklower 	int f;
368*45223Ssklower 	char *msg;
369*45223Ssklower {
370*45223Ssklower 	register char *p;
371*45223Ssklower 	char buf[BUFSIZ], *index();
372*45223Ssklower 
373*45223Ssklower 	p = buf;
374*45223Ssklower 	if (f == net)
375*45223Ssklower 		*p++ = 0;
376*45223Ssklower 	strcpy(p, "x29d: ");
377*45223Ssklower 	strcat(p, msg);
378*45223Ssklower 	strcat(p, "\n");
379*45223Ssklower 	(void) write(f, p, (index(p, '\n')-p)+1);
380*45223Ssklower 	exit(1);
381*45223Ssklower }
382*45223Ssklower 
383*45223Ssklower fatalperror(msg, err)
384*45223Ssklower char *msg;
385*45223Ssklower {
386*45223Ssklower 	char buf[BUFSIZ];
387*45223Ssklower 	extern char *sys_errlist[];
388*45223Ssklower 
389*45223Ssklower 	strcpy(buf, msg);
390*45223Ssklower 	strcat(buf, ": ");
391*45223Ssklower 	strcat(buf, sys_errlist[err]);
392*45223Ssklower 	fatal(net, buf);
393*45223Ssklower }
394*45223Ssklower 
395*45223Ssklower /*
396*45223Ssklower  * Main loop.  Select from pty and network, and
397*45223Ssklower  * hand data to iti receiver.
398*45223Ssklower  */
399*45223Ssklower x29d()
400*45223Ssklower {
401*45223Ssklower 	register int pcc, fcc, cc;
402*45223Ssklower 	register char *fbp;
403*45223Ssklower 	int pgrp, x25_interrupt(), on = 1;
404*45223Ssklower 	char hostname[32];
405*45223Ssklower 
406*45223Ssklower 	ioctl(net, FIONBIO, (char *)&on);
407*45223Ssklower 	ioctl(pty, FIONBIO, (char *)&on);
408*45223Ssklower 	ioctl(pty, TIOCPKT, (char *)&on);
409*45223Ssklower 	ioctl(pty, TIOCREMECHO, (char *)&on);	/* enable special pty mode */
410*45223Ssklower 	signal(SIGPIPE, SIG_IGN);	/* why not cleanup?  --kwl */
411*45223Ssklower 	signal(SIGTSTP, SIG_IGN);
412*45223Ssklower 	signal(SIGCHLD, cleanup);
413*45223Ssklower 	signal(SIGHUP, cleanup);
414*45223Ssklower 
415*45223Ssklower 	signal(SIGTTOU, SIG_IGN);
416*45223Ssklower 	signal(SIGURG, x25_interrupt);	/* for out-of-band data */
417*45223Ssklower 	pgrp = -getpgrp(0);
418*45223Ssklower 	ioctl(net, SIOCSPGRP, (char *)&pgrp);
419*45223Ssklower 
420*45223Ssklower 	if (netp->n_proflen)
421*45223Ssklower 		(void) write(net, netp->n_profile, netp->n_proflen);
422*45223Ssklower 
423*45223Ssklower 	/*
424*45223Ssklower 	 * Show banner that getty never gave.
425*45223Ssklower 	 */
426*45223Ssklower 	if (send_banner) {
427*45223Ssklower 		gethostname(hostname, sizeof (hostname));
428*45223Ssklower #ifdef BSD4_3
429*45223Ssklower 		strcpy(pibuf+1, "\r\n\r\n4.3 BSD UNIX (");
430*45223Ssklower #else
431*45223Ssklower 		strcpy(pibuf+1, "\r\n\r\n4.2 BSD UNIX (");
432*45223Ssklower #endif
433*45223Ssklower 		strcat(pibuf+1, hostname);
434*45223Ssklower 		strcat(pibuf+1, ")\r\n\r\n");
435*45223Ssklower 		pcc = strlen(pibuf+1) + 1;
436*45223Ssklower 	} else
437*45223Ssklower 		pcc = 0;
438*45223Ssklower 
439*45223Ssklower 	fcc = 0;
440*45223Ssklower 	for (;;) {
441*45223Ssklower 		int ibits, obits;
442*45223Ssklower 
443*45223Ssklower 		ibits = obits = 0;
444*45223Ssklower 		/*
445*45223Ssklower 		 * Never look for input if there's still
446*45223Ssklower 		 * stuff in the corresponding output buffer
447*45223Ssklower 		 */
448*45223Ssklower 		if (fcc >= 0)			/* net connection alive? */
449*45223Ssklower 			if (fcc && pcc >= 0)	/* output pending? */
450*45223Ssklower 				obits |= (1 << pty);
451*45223Ssklower 			else
452*45223Ssklower 				if (pcc >= 0)	/* pty still alive? */
453*45223Ssklower 					ibits |= (1 << net);
454*45223Ssklower 		if (pcc >= 0)			/* pty connection alive? */
455*45223Ssklower 			if (pcc && fcc >= 0)	/* output pending? */
456*45223Ssklower 				obits |= (1 << net);
457*45223Ssklower 			else
458*45223Ssklower 				if (fcc >= 0)	/* net still alive? */
459*45223Ssklower 					ibits |= (1 << pty);
460*45223Ssklower 		if(ibits == 0 && obits == 0)
461*45223Ssklower 			break;
462*45223Ssklower 		(void) select(16, &ibits, &obits, (int *)0, 0);
463*45223Ssklower 		if (ibits == 0 && obits == 0) {
464*45223Ssklower 			sleep(5);
465*45223Ssklower 			continue;
466*45223Ssklower 		}
467*45223Ssklower 
468*45223Ssklower 		/*
469*45223Ssklower 		 * Something to read from the network...
470*45223Ssklower 		 */
471*45223Ssklower 		if (ibits & (1 << net)) {
472*45223Ssklower 			fcc = read(net, fibuf, BUFSIZ);
473*45223Ssklower 			fbp = fibuf+1;
474*45223Ssklower 			if (fcc < 0 && errno == EWOULDBLOCK)
475*45223Ssklower 				fcc = 0;
476*45223Ssklower 			else if(fcc <= 0)
477*45223Ssklower 				fcc = -1;
478*45223Ssklower 			else {
479*45223Ssklower 				if (tracefn)
480*45223Ssklower 					x29d_trace("netread", fibuf, fcc);
481*45223Ssklower 				if(fibuf[0] & Q_BIT) {
482*45223Ssklower 					x29_qbit(fcc);
483*45223Ssklower 					fcc = 0;
484*45223Ssklower 				} else
485*45223Ssklower 					fcc--;
486*45223Ssklower 			}
487*45223Ssklower 		}
488*45223Ssklower 
489*45223Ssklower 		/*
490*45223Ssklower 		 * Something to read from the pty...
491*45223Ssklower 		 */
492*45223Ssklower 		if (ibits & (1 << pty)) {
493*45223Ssklower 			pcc = read(pty, pibuf, packet_size+1);
494*45223Ssklower 			if (pcc < 0 && errno == EWOULDBLOCK)
495*45223Ssklower 				pcc = 0;
496*45223Ssklower 			else if (pcc <= 0)
497*45223Ssklower 				pcc = -1;
498*45223Ssklower 			else if(pibuf[0] != 0) {	/* non-data packet */
499*45223Ssklower 				if (pibuf[0] & TIOCPKT_IOCTL)
500*45223Ssklower 					pcc = set_x29_parameters();
501*45223Ssklower 				else
502*45223Ssklower 					pcc = 0;
503*45223Ssklower 			} else				/* data packet */
504*45223Ssklower 				pibuf[0] = 0;
505*45223Ssklower 		}
506*45223Ssklower 
507*45223Ssklower 		if ((obits & (1<<net)) && pcc > 0)
508*45223Ssklower 			if((cc = write(net, pibuf, pcc)) == pcc) {
509*45223Ssklower 				if(tracefn)
510*45223Ssklower 					x29d_trace("netwrite", pibuf, pcc);
511*45223Ssklower 				pcc = 0;
512*45223Ssklower 			} else {
513*45223Ssklower 				extern char *sys_errlist[];
514*45223Ssklower 
515*45223Ssklower 				if(tracefn)
516*45223Ssklower 					x29d_trace("netwrite",
517*45223Ssklower 						sys_errlist[errno],
518*45223Ssklower 						strlen(sys_errlist[errno]));
519*45223Ssklower 
520*45223Ssklower 			}
521*45223Ssklower 
522*45223Ssklower 		if ((obits & (1 << pty)) && fcc > 0) {
523*45223Ssklower 			cc = write(pty, fbp, fcc);
524*45223Ssklower 			if (cc > 0) {
525*45223Ssklower 				fcc -= cc;
526*45223Ssklower 				fbp += cc;
527*45223Ssklower 			}
528*45223Ssklower 		}
529*45223Ssklower 	}
530*45223Ssklower 	cleanup();
531*45223Ssklower }
532*45223Ssklower 
533*45223Ssklower 
534*45223Ssklower /*
535*45223Ssklower  * Send interrupt to process on other side of pty.
536*45223Ssklower  * If it is in raw mode, just write NULL;
537*45223Ssklower  * otherwise, write intr char.
538*45223Ssklower  */
539*45223Ssklower 
540*45223Ssklower x25_interrupt()
541*45223Ssklower {
542*45223Ssklower 	struct sgttyb b;
543*45223Ssklower 	struct tchars tchars;
544*45223Ssklower 	int zero = 0;
545*45223Ssklower 
546*45223Ssklower 	signal(SIGURG, x25_interrupt);
547*45223Ssklower 	ioctl(pty, TIOCGETP, (char *)&b);
548*45223Ssklower 	if (b.sg_flags & RAW)
549*45223Ssklower 		(void) write(pty, "\0", 1);
550*45223Ssklower 	else {
551*45223Ssklower 		ioctl(pty, TIOCFLUSH, (char *)&zero);
552*45223Ssklower 		ioctl(pty, TIOCGETC, (char *)&tchars);
553*45223Ssklower 		(void) write(pty, &tchars.t_intrc, 1);
554*45223Ssklower 	}
555*45223Ssklower }
556*45223Ssklower 
557*45223Ssklower cleanup()
558*45223Ssklower {
559*45223Ssklower 	struct sgttyb sg;
560*45223Ssklower 	struct stat st;
561*45223Ssklower 
562*45223Ssklower 	ioctl(pty, TIOCGETP, (char *)&sg);    /* flushes output buffer */
563*45223Ssklower 	ioctl(pty, TIOCSETP, (char *)&sg);
564*45223Ssklower 	(void) stat(line, &st);
565*45223Ssklower 	rmut();
566*45223Ssklower 	vhangup();			/* XXX */
567*45223Ssklower 	setuid(st.st_uid);
568*45223Ssklower 	exit(1);
569*45223Ssklower }
570*45223Ssklower 
571*45223Ssklower /*
572*45223Ssklower  * Map unix tty modes and special characters
573*45223Ssklower  * into x29 parameters.
574*45223Ssklower  */
575*45223Ssklower 
576*45223Ssklower set_x29_parameters()
577*45223Ssklower {
578*45223Ssklower 	register char *p;
579*45223Ssklower 	register int f;
580*45223Ssklower 	struct sgttyb b;
581*45223Ssklower 
582*45223Ssklower 	if (netp->n_type == X25NET)
583*45223Ssklower 		return (0);
584*45223Ssklower 	ioctl(pty, TIOCGETP, (char *)&b);
585*45223Ssklower 	f = b.sg_flags;
586*45223Ssklower 	p = pibuf;
587*45223Ssklower 	*p++ = Q_BIT;
588*45223Ssklower 	*p++ = X29_SET_PARMS;
589*45223Ssklower 	*p++ = X29_ESCAPE_TO_CMD_CODE;	*p++ = (f & (RAW|CBREAK)) == 0;
590*45223Ssklower 	*p++ = X29_ECHO_CODE;		*p++ = (f & ECHO) != 0;
591*45223Ssklower 	*p++ = X29_FORWARDING_SIGNAL_CODE;	*p++ = (f & (RAW|CBREAK)) ? 0 : 126;
592*45223Ssklower 
593*45223Ssklower 	/*
594*45223Ssklower 	 * The value of 10 (0.5 seconds) for the idle timer when
595*45223Ssklower 	 * in raw or cbreak mode is a compromise value.  For good
596*45223Ssklower 	 * interactive response this value should be as low as
597*45223Ssklower 	 * possible; for reasonable efficiency with file transfers
598*45223Ssklower 	 * this value should be at fairly high.  This number should
599*45223Ssklower 	 * be changed to suit local requirements.
600*45223Ssklower 	 */
601*45223Ssklower 
602*45223Ssklower 	*p++ = X29_IDLE_TIMER_CODE;	*p++ = (f & (RAW|CBREAK)) ? 10 : 0;
603*45223Ssklower 	*p++ = X29_AUX_DEV_CONTROL_CODE;*p++ = (f & TANDEM) != 0;
604*45223Ssklower 	*p++ = X29_XON_XOFF_CODE;	*p++ = (f & RAW) == 0;
605*45223Ssklower 	if(netp->n_type == CCITT1980) {
606*45223Ssklower 		struct ltchars ltc;
607*45223Ssklower 
608*45223Ssklower 		ioctl(pty, TIOCGLTC, (char *)&ltc);
609*45223Ssklower 		*p++ = X29_LF_AFTER_CR;
610*45223Ssklower 		*p++ = (f & (RAW|CBREAK) || (f & ECHO) == 0) ? 0 : 4;
611*45223Ssklower 		*p++ = X29_EDITING;
612*45223Ssklower 		*p++ = (f & (RAW|CBREAK)) == 0;
613*45223Ssklower 		*p++ = X29_CHARACTER_DELETE;
614*45223Ssklower 		*p++ = (f & (RAW|CBREAK)) || b.sg_erase & 0200 ?
615*45223Ssklower 			0 : b.sg_erase;
616*45223Ssklower 		*p++ = X29_LINE_DELETE;
617*45223Ssklower 		*p++ = (f & (RAW|CBREAK)) || b.sg_kill & 0200 ?
618*45223Ssklower 			0 : b.sg_kill;
619*45223Ssklower 		*p++ = X29_LINE_DISPLAY;
620*45223Ssklower 		*p++ = (f & (RAW|CBREAK)) || ltc.t_rprntc & 0200 ?
621*45223Ssklower 			0 : ltc.t_rprntc;
622*45223Ssklower 	}
623*45223Ssklower 	return (p - pibuf);
624*45223Ssklower }
625*45223Ssklower 
626*45223Ssklower /*
627*45223Ssklower  * Process Q BIT (control) packets from the net.
628*45223Ssklower  * The only message that we are interested in are
629*45223Ssklower  * those indicating output is being discarded.
630*45223Ssklower  */
631*45223Ssklower 
632*45223Ssklower x29_qbit(n)
633*45223Ssklower {
634*45223Ssklower 	register char *p;
635*45223Ssklower 
636*45223Ssklower 	switch (fibuf[1]) {
637*45223Ssklower 	case X29_SET_PARMS:
638*45223Ssklower 	case X29_SET_AND_READ_PARMS:
639*45223Ssklower 	case X29_PARAMETER_INDICATION:
640*45223Ssklower 	case X29_INDICATION_OF_BREAK:
641*45223Ssklower 		for(p = &fibuf[2]; p < fibuf+n; p++) {
642*45223Ssklower 			if(*p == X29_TRANSMISSION_SPEED_CODE) {
643*45223Ssklower 				static char speeds[] = {
644*45223Ssklower 					B110, B0, B300, B1200, B600,
645*45223Ssklower 					B0, B0, B0, B0, B0, B0, B0,
646*45223Ssklower 					B2400, B4800, B9600, EXTA };
647*45223Ssklower 				struct sgttyb b;
648*45223Ssklower 
649*45223Ssklower 				if(*++p >= 0 && *p < sizeof(speeds)) {
650*45223Ssklower 					ioctl(pty, TIOCGETP, (char *)&b);
651*45223Ssklower 					b.sg_ispeed = b.sg_ospeed = speeds[*p];
652*45223Ssklower 					ioctl(pty, TIOCSETN, (char *)&b);
653*45223Ssklower 				}
654*45223Ssklower 			} else if(*p == X29_DISCARD_OUTPUT_CODE && *++p != 0) {
655*45223Ssklower 				char message[4];
656*45223Ssklower 
657*45223Ssklower 				/*
658*45223Ssklower 				 * Always re-enable normal output
659*45223Ssklower 				 */
660*45223Ssklower 				message[0] = Q_BIT;
661*45223Ssklower 				message[1] = X29_SET_PARMS;
662*45223Ssklower 				message[2] = X29_DISCARD_OUTPUT_CODE;
663*45223Ssklower 				message[3] = 0;
664*45223Ssklower 				(void) write(net, message, sizeof(message));
665*45223Ssklower 				if(tracefn)
666*45223Ssklower 					x29d_trace("netwrite", message, 4);
667*45223Ssklower 			}
668*45223Ssklower 		}
669*45223Ssklower 		return;
670*45223Ssklower 
671*45223Ssklower 	default: {
672*45223Ssklower 			register char *p2;
673*45223Ssklower 			char buf[BUFSIZ*4];
674*45223Ssklower 			static int fd;
675*45223Ssklower 
676*45223Ssklower 			/*
677*45223Ssklower 			 * Bad news - we received an x29 error message or
678*45223Ssklower 			 * some other unknown packet.  Dump the contents
679*45223Ssklower 			 * of the packet on the console.
680*45223Ssklower 			 */
681*45223Ssklower 			p = buf;
682*45223Ssklower 			for(p2 = "x29d: unknown q-bit packet: "; *p++ = *p2++; );
683*45223Ssklower 			for(p2 = fibuf+1; p2 < fibuf+n; p2++)
684*45223Ssklower 				if(*p2 >= ' ' && *p2 < 0177)
685*45223Ssklower 					*p++ = *p2;
686*45223Ssklower 				else {
687*45223Ssklower 					*p++ = '\\';
688*45223Ssklower 					*p++ = ((*p2 & 0300) >> 6) + '0';
689*45223Ssklower 					*p++ = ((*p2 & 070) >> 3) + '0';
690*45223Ssklower 					*p++ = (*p2 & 07) + '0';
691*45223Ssklower 				}
692*45223Ssklower 			*p++ = '\n';
693*45223Ssklower 			if(fd <= 0)
694*45223Ssklower 				fd = open(console, 1);
695*45223Ssklower 			(void) write(fd, buf, p-buf);
696*45223Ssklower 		}
697*45223Ssklower 	}
698*45223Ssklower }
699*45223Ssklower 
700*45223Ssklower /*
701*45223Ssklower  * HACK!
702*45223Ssklower  * This program does not use or need any stdio routines.
703*45223Ssklower  * Defining this procedure prevents all of the stdio
704*45223Ssklower  * code from being loaded.
705*45223Ssklower  */
706*45223Ssklower 
707*45223Ssklower exit(code)
708*45223Ssklower {
709*45223Ssklower 	_exit(code);
710*45223Ssklower }
711*45223Ssklower 
712*45223Ssklower #include <utmp.h>
713*45223Ssklower 
714*45223Ssklower struct	utmp wtmp;
715*45223Ssklower char	wtmpf[]	= "/usr/adm/wtmp";
716*45223Ssklower char	utmp[] = "/etc/utmp";
717*45223Ssklower #define SCPYN(a, b)	strncpy(a, b, sizeof (a))
718*45223Ssklower #define SCMPN(a, b)	strncmp(a, b, sizeof (a))
719*45223Ssklower 
720*45223Ssklower rmut()
721*45223Ssklower {
722*45223Ssklower 	register int f, found = 0;
723*45223Ssklower 
724*45223Ssklower 	f = open(utmp, 2);
725*45223Ssklower 	if (f >= 0) {
726*45223Ssklower 		while(read(f, (char *)&wtmp, sizeof (wtmp)) == sizeof (wtmp)) {
727*45223Ssklower 			if (SCMPN(wtmp.ut_line, line+5) || wtmp.ut_name[0]==0)
728*45223Ssklower 				continue;
729*45223Ssklower 			(void) lseek(f, -(long)sizeof (wtmp), 1);
730*45223Ssklower 			SCPYN(wtmp.ut_name, "");
731*45223Ssklower 			SCPYN(wtmp.ut_host, "");
732*45223Ssklower 			time(&wtmp.ut_time);
733*45223Ssklower 			(void) write(f, (char *)&wtmp, sizeof (wtmp));
734*45223Ssklower 			found++;
735*45223Ssklower 		}
736*45223Ssklower 		close(f);
737*45223Ssklower 	}
738*45223Ssklower 	if (found) {
739*45223Ssklower 		f = open(wtmpf, 1);
740*45223Ssklower 		if (f >= 0) {
741*45223Ssklower 			SCPYN(wtmp.ut_line, line+5);
742*45223Ssklower 			SCPYN(wtmp.ut_name, "");
743*45223Ssklower 			SCPYN(wtmp.ut_host, "");
744*45223Ssklower 			time(&wtmp.ut_time);
745*45223Ssklower 			(void) lseek(f, (long)0, 2);
746*45223Ssklower 			(void) write(f, (char *)&wtmp, sizeof (wtmp));
747*45223Ssklower 			close(f);
748*45223Ssklower 		}
749*45223Ssklower 	}
750*45223Ssklower 	chmod(line, 0666);
751*45223Ssklower 	chown(line, 0, 0);
752*45223Ssklower 	line[strlen("/dev/")] = 'p';
753*45223Ssklower 	chmod(line, 0666);
754*45223Ssklower 	chown(line, 0, 0);
755*45223Ssklower }
756*45223Ssklower 
757*45223Ssklower x29d_trace(s, bp, n)
758*45223Ssklower char *s, *bp;
759*45223Ssklower {
760*45223Ssklower 	static int fd;
761*45223Ssklower 	char buf[BUFSIZ*4];
762*45223Ssklower 	register char *p1, *p2;
763*45223Ssklower 
764*45223Ssklower 	for(p1 = buf; *s; *p1++ = *s++);
765*45223Ssklower 	*p1++ = ':';
766*45223Ssklower 	*p1++ = ' ';
767*45223Ssklower 	for(p2=bp; p2 < bp+n; p2++)
768*45223Ssklower 		if(*p2 >= ' ' && *p2 < 0177)
769*45223Ssklower 			*p1++ = *p2;
770*45223Ssklower 		else {
771*45223Ssklower 			*p1++ = '\\';
772*45223Ssklower 			*p1++ = ((*p2 & 0300) >> 6) + '0';
773*45223Ssklower 			*p1++ = ((*p2 & 070) >> 3) + '0';
774*45223Ssklower 			*p1++ = (*p2 & 07) + '0';
775*45223Ssklower 		}
776*45223Ssklower 	*p1++ = '\n';
777*45223Ssklower 	if(fd <= 0)
778*45223Ssklower 		fd = creat(tracefn, 0666);
779*45223Ssklower 	(void) write(fd, buf, p1-buf);
780*45223Ssklower }
781