xref: /csrg-svn/usr.bin/uucp/uucico/cico.c (revision 18616)
113639Ssam #ifndef lint
2*18616Sralph static char sccsid[] = "@(#)cico.c	5.6 (Berkeley) 04/10/85";
313639Ssam #endif
413639Ssam 
513639Ssam #include "uucp.h"
613639Ssam #include <signal.h>
713639Ssam #include <setjmp.h>
817767Sralph #ifdef	USG
913639Ssam #include <termio.h>
1013639Ssam #endif
1117767Sralph #ifndef	USG
1213639Ssam #include <sgtty.h>
1313639Ssam #endif
1417767Sralph #ifdef BSDTCP
1517767Sralph #include <netdb.h>
1617767Sralph #include <netinet/in.h>
1717767Sralph #include <sys/socket.h>
1817767Sralph #endif BSDTCP
1917767Sralph #include <sys/stat.h>
2017767Sralph #include "uust.h"
2117767Sralph #include "uusub.h"
2213639Ssam 
2317767Sralph jmp_buf Sjbuf;
2417767Sralph jmp_buf Pipebuf;
2513639Ssam 
2617767Sralph /*  call fail text  */
2713639Ssam char *Stattext[] = {
2813639Ssam 	"",
2913639Ssam 	"BAD SYSTEM",
3017767Sralph 	"WRONG TIME TO CALL",
3113639Ssam 	"SYSTEM LOCKED",
3213639Ssam 	"NO DEVICE",
3313639Ssam 	"DIAL FAILED",
3413639Ssam 	"LOGIN FAILED",
3513639Ssam 	"BAD SEQUENCE"
3617767Sralph };
3713639Ssam 
3817767Sralph /*  call fail codes  */
3917767Sralph int Stattype[] = {
4017767Sralph 	0,
4117767Sralph 	0,
4217767Sralph 	SS_WRONGTIME,
4317767Sralph 	0,
4417767Sralph 	SS_NODEVICE,
4517767Sralph 	SS_FAIL,
4617767Sralph 	SS_FAIL,
4717767Sralph 	SS_BADSEQ
4817767Sralph };
4913639Ssam 
5013639Ssam 
5113639Ssam int Errorrate = 0;
5217767Sralph int ReverseRole = 0;
5317767Sralph int StdErrIsTty = 0;
5417767Sralph int Role = SLAVE;
5517767Sralph int onesys = 0;
56*18616Sralph int turntime = 30 * 60;	/* 30 minutes expressed in seconds */
5717767Sralph extern int LocalOnly;
58*18616Sralph extern char MaxGrade, DefMaxGrade;
59*18616Sralph extern char Myfullname[];
6017767Sralph 
6117767Sralph #ifdef	USG
6213639Ssam struct termio Savettyb;
6313639Ssam #endif
6417767Sralph #ifndef	USG
6513639Ssam struct sgttyb Savettyb;
6613639Ssam #endif
6713639Ssam 
6813639Ssam /*******
6913639Ssam  *	cico - this program is used  to place a call to a
7013639Ssam  *	remote machine, login, and copy files between the two machines.
7113639Ssam  */
7213639Ssam 
7313639Ssam main(argc, argv)
7413639Ssam register char *argv[];
7513639Ssam {
7613639Ssam 	register int ret;
7713639Ssam 	int seq;
7813639Ssam 	char wkpre[NAMESIZE], file[NAMESIZE];
7917767Sralph 	char msg[MAXFULLNAME], *q, **alias;
8013639Ssam 	register char *p;
8113639Ssam 	extern onintr(), timeout(), setdebug();
8213639Ssam 	extern char *pskip();
8313639Ssam 	char rflags[30];
8413639Ssam 	char *ttyn;
8517767Sralph #if defined(VMS) && defined(BSDTCP)
8617767Sralph 	u_long Hostnumber = 0;
8717767Sralph #endif VMS && BSDTCP
8813639Ssam 
8913639Ssam 	strcpy(Progname, "uucico");
9013639Ssam 	uucpname(Myname);
9113639Ssam 
9213639Ssam 	signal(SIGINT, onintr);
9313639Ssam 	signal(SIGHUP, onintr);
9413639Ssam 	signal(SIGQUIT, onintr);
9513639Ssam 	signal(SIGTERM, onintr);
9613639Ssam 	signal(SIGPIPE, onintr);	/* 4.1a tcp-ip stupidity */
9713639Ssam 	signal(SIGFPE, setdebug);
9813639Ssam 	ret = guinfo(getuid(), User, msg);
9913639Ssam 	strcpy(Loginuser, User);
10017767Sralph 	ASSERT(ret == 0, "BAD UID", CNULL, ret);
10113639Ssam 
10217767Sralph #ifdef BSD4_2
10317767Sralph 	setlinebuf(stderr);
10417767Sralph #endif
10513639Ssam 	rflags[0] = '\0';
10613639Ssam 	umask(WFMASK);
10713639Ssam 	strcpy(Rmtname, Myname);
10813639Ssam 	Ifn = Ofn = -1;
10913639Ssam 	while(argc>1 && argv[1][0] == '-'){
11013639Ssam 		switch(argv[1][1]){
11113639Ssam 		case 'd':
11213639Ssam 			Spool = &argv[1][2];
11313639Ssam 			break;
11413639Ssam 		case 'g':
115*18616Sralph 		case 'p':
116*18616Sralph 			MaxGrade = DefMaxGrade = argv[1][2];
11713639Ssam 			break;
11813639Ssam 		case 'r':
11913639Ssam 			Role = atoi(&argv[1][2]);
12013639Ssam 			break;
12117767Sralph 		case 'R':
12217767Sralph 			ReverseRole++;
12317767Sralph 			Role = MASTER;
12417767Sralph 			break;
12513639Ssam 		case 's':
12613639Ssam 			sprintf(Rmtname, "%.7s", &argv[1][2]);
12713639Ssam 			if (Rmtname[0] != '\0')
12813639Ssam 				onesys = 1;
12913639Ssam 			break;
13013639Ssam 		case 'x':
13117767Sralph 			chkdebug();
13213639Ssam 			Debug = atoi(&argv[1][2]);
13313639Ssam 			if (Debug <= 0)
13413639Ssam 				Debug = 1;
13513639Ssam 			strcat(rflags, argv[1]);
13613639Ssam 			logent("ENABLED", "DEBUG");
13713639Ssam 			break;
138*18616Sralph 		case 't':
139*18616Sralph 			turntime = atoi(&argv[1][2])*60;/* minutes to seconds */
140*18616Sralph 			break;
14117767Sralph 		case 'L':	/* local calls only */
14217767Sralph 			LocalOnly++;
14317767Sralph 			break;
14417767Sralph #if defined(VMS) && defined(BSDTCP)
14517767Sralph 		case 'h':
14617767Sralph 			Hostnumber = inet_addr(&argv[1][2]);
14717767Sralph 			break;
14817767Sralph #endif VMS && BSDTCP
14913639Ssam 		default:
15017767Sralph 			printf("unknown flag %s (ignored)\n", argv[1]);
15113639Ssam 			break;
15213639Ssam 		}
15313639Ssam 		--argc;  argv++;
15413639Ssam 	}
15513639Ssam 
15617767Sralph 	while (argc > 1) {
15717767Sralph 		printf("unknown argument %s (ignored)\n", argv[1]);
15817767Sralph 		--argc; argv++;
15917767Sralph 	}
16017767Sralph 
16117767Sralph 	/* Try to run as uucp -- rti!trt */
16217767Sralph 	setgid(getegid());
16317767Sralph 	setuid(geteuid());
16417767Sralph #ifdef	TIOCNOTTY
16517767Sralph 	/*
16617767Sralph 	 * detach uucico from controlling terminal
16717767Sralph 	 * to defend against rlogind sending us a SIGKILL (!!!)
16817767Sralph 	 */
16917767Sralph 	if (Role == MASTER && (ret = open("/dev/tty", 2)) >= 0) {
17017767Sralph 		ioctl(ret, TIOCNOTTY, STBNULL);
17117767Sralph 		close(ret);
17217767Sralph 	}
17317767Sralph #endif TIOCNOTTY
17417767Sralph #ifdef BSD4_2
17517767Sralph 	if (getpgrp(0) == 0) { /*We have no controlling terminal */
17617767Sralph 		setpgrp(0, getpid());
17717767Sralph 	}
17817767Sralph #endif BSD4_2
17917767Sralph 
18017767Sralph 	ret = subchdir(Spool);
18117767Sralph 	ASSERT(ret >= 0, "CHDIR FAILED", Spool, ret);
18213639Ssam 	strcpy(Wrkdir, Spool);
18313639Ssam 
18413639Ssam 	if (Role == SLAVE) {
18517767Sralph 		/* check for /etc/nologin */
18617767Sralph 		ultouch();	/* sets nologinflag as a side effect */
18717767Sralph 		if (nologinflag) {
18817767Sralph 			logent(NOLOGIN, "UUCICO SHUTDOWN");
18917767Sralph 			if (Debug)
19017767Sralph 				logent("DEBUGGING", "continuing anyway");
19117767Sralph 			else
19217767Sralph 				cleanup(1);
19317767Sralph 		}
19417767Sralph #ifdef	TCPIP
19517767Sralph 		/*
19617767Sralph 		 * Determine if we are on TCPIP
19717767Sralph 		 */
19817767Sralph 		if (isatty(0) ==  0) {
19917767Sralph 			IsTcpIp = 1;
20017767Sralph 			DEBUG(4, "TCPIP connection -- ioctl-s disabled\n", CNULL);
20117767Sralph 		}
20217767Sralph #endif TCPIP
20313639Ssam 		/* initial handshake */
20413639Ssam 		onesys = 1;
20517767Sralph 		if (!IsTcpIp) {
20617767Sralph #ifdef	USG
20713639Ssam 			ret = ioctl(0, TCGETA, &Savettyb);
20813639Ssam 			Savettyb.c_cflag = (Savettyb.c_cflag & ~CS8) | CS7;
20913639Ssam 			Savettyb.c_oflag |= OPOST;
21013639Ssam 			Savettyb.c_lflag |= (ISIG|ICANON|ECHO);
21117767Sralph #else !USG
21213639Ssam 			ret = ioctl(0, TIOCGETP, &Savettyb);
21313639Ssam 			Savettyb.sg_flags |= ECHO;
21413639Ssam 			Savettyb.sg_flags &= ~RAW;
21517767Sralph #endif !USG
21613639Ssam 		}
21713639Ssam 		Ifn = 0;
21813639Ssam 		Ofn = 1;
21913639Ssam 		fixmode(Ifn);
22017767Sralph 		sprintf(file,"%s/%d", RMTDEBUG, getpid());
22117767Sralph #ifdef VMS
22217767Sralph 		/* hold the version number down */
22317767Sralph 		unlink(file);
22417767Sralph #endif
22517767Sralph 		freopen(file, "w", stderr);
22617767Sralph #ifdef BSD4_2
22717767Sralph 		setlinebuf(stderr);
22817767Sralph #else  !BSD4_2
22917767Sralph 		setbuf(stderr, NULL);
23017767Sralph #endif !BSD4_2
231*18616Sralph 		sprintf(msg, "here=%s", Myfullname);
23217767Sralph 		omsg('S', msg, Ofn);
23313639Ssam 		signal(SIGALRM, timeout);
23413639Ssam 		alarm(MAXMSGTIME);
23513639Ssam 		if (setjmp(Sjbuf)) {
23613639Ssam 			/* timed out */
23717767Sralph 			if (!IsTcpIp) {
23817767Sralph #ifdef	USG
23913639Ssam 				ret = ioctl(0, TCSETA, &Savettyb);
24013639Ssam #endif
24117767Sralph #ifndef	USG
24213639Ssam 				ret = ioctl(0, TIOCSETP, &Savettyb);
24313639Ssam #endif
24413639Ssam 			}
24517767Sralph 			cleanup(0);
24613639Ssam 		}
24713639Ssam 		for (;;) {
24813639Ssam 			ret = imsg(msg, Ifn);
24913639Ssam 			if (ret != 0) {
25013639Ssam 				alarm(0);
25117767Sralph 				if (!IsTcpIp) {
25217767Sralph #ifdef	USG
25313639Ssam 					ret = ioctl(0, TCSETA, &Savettyb);
25413639Ssam #endif
25517767Sralph #ifndef	USG
25613639Ssam 					ret = ioctl(0, TIOCSETP, &Savettyb);
25713639Ssam #endif
25813639Ssam 				}
25917767Sralph 				cleanup(0);
26013639Ssam 			}
26113639Ssam 			if (msg[0] == 'S')
26213639Ssam 				break;
26313639Ssam 		}
26413639Ssam 		alarm(0);
26513639Ssam 		q = &msg[1];
26613639Ssam 		p = pskip(q);
26713639Ssam 		sprintf(Rmtname, "%.7s", q);
26817767Sralph 		sprintf(wkpre,"%s/%s", RMTDEBUG, Rmtname);
26917767Sralph 		unlink(wkpre);
27017767Sralph 		if (link(file, wkpre) == 0)
27117767Sralph 			unlink(file);
27213639Ssam 		DEBUG(4, "sys-%s\n", Rmtname);
27317767Sralph #ifdef BSDTCP
27417767Sralph 		/* we must make sure they are really who they say they
27517767Sralph 		 * are. We compare the hostnumber with the number in the hosts
27617767Sralph 		 * table for the site they claim to be.
27717767Sralph 		 */
27817767Sralph 		if (IsTcpIp) {
27917767Sralph 			struct hostent *hp;
28017767Sralph 			char *cpnt, *inet_ntoa();
28117767Sralph 			int fromlen;
28217767Sralph 			struct sockaddr_in from;
28317767Sralph 
28417767Sralph #ifndef	VMS
28517767Sralph 			fromlen = sizeof(from);
28617767Sralph 			if (getpeername(0, &from, &fromlen) < 0) {
28717767Sralph 				logent(Rmtname, "NOT A TCP CONNECTION");
28817767Sralph 				omsg('R', "NOT TCP", Ofn);
28917767Sralph 				cleanup(0);
29017767Sralph 			}
29117767Sralph #else	VMS
29217767Sralph 			from.sin_addr.s_addr = Hostnumber;
29317767Sralph 			from.sin_family = AF_INET;
29417767Sralph #endif	VMS
29517767Sralph 			hp = gethostbyaddr(&from.sin_addr,
29617767Sralph 				sizeof (struct in_addr), from.sin_family);
29717767Sralph 			if (hp == 0) {
29817767Sralph 				/* security break or just old host table? */
29917767Sralph 				logent(Rmtname, "UNKNOWN IP-HOST Name =");
30017767Sralph 				cpnt = inet_ntoa(from.sin_addr),
30117767Sralph 				logent(cpnt, "UNKNOWN IP-HOST Number =");
30217767Sralph 				sprintf(wkpre, "%s/%s isn't in my host table",
30317767Sralph 					Rmtname, cpnt);
30417767Sralph 				omsg('R' ,wkpre ,Ofn);
30517767Sralph 				cleanup(0);
30617767Sralph 			}
30717767Sralph 			if (Debug>99)
30817767Sralph 				logent(Rmtname,"Request from IP-Host name =");
30917767Sralph 			/* The following is to determine if the name given us by
31017767Sralph 			 * the Remote uucico matches any of the names(aliases)
31117767Sralph 			 * given its network number (remote machine) in our
31217767Sralph 			 * host table.
31317767Sralph 			 */
31417767Sralph 			if (strncmp(q, hp->h_name, 7) == 0) {
31517767Sralph 				if (Debug > 99)
31617767Sralph 					logent(q,"Found in host Tables");
31717767Sralph 			} else { /* Scan The host aliases */
31817767Sralph 				for(alias=hp->h_aliases; *alias!=0 &&
31917767Sralph 				    strncmp(q, *alias, 7) != 0; ++alias)
32017767Sralph 					;
32117767Sralph 				if (strncmp(q, *alias, 7) != 0) {
32217767Sralph 					logent(q, "FORGED HOSTNAME");
32317767Sralph 					logent(inet_ntoa(from.sin_addr), "ORIGINATED AT");
32417767Sralph 					omsg('R',"You're not who you claim to be");
32517767Sralph 					cleanup(0);
32617767Sralph 				}
32717767Sralph #ifdef DEBUG
32817767Sralph 				if (Debug> 99)
32917767Sralph 					logent(q,"Found in host Tables");
33017767Sralph #endif
33117767Sralph 			}
33217767Sralph 		}
33317767Sralph #endif	BSDTCP
33417767Sralph 
33517767Sralph #ifdef	NOSTRANGERS
33617767Sralph 		/* If we don't know them, we won't talk to them... */
337*18616Sralph 		if (versys(&Rmtname)) {
33817767Sralph 			logent(Rmtname, "UNKNOWN HOST");
33917767Sralph 			omsg('R', "You are unknown to me", Ofn);
34017767Sralph 			cleanup(0);
34117767Sralph 		}
34217767Sralph #endif	NOSTRANGERS
34313639Ssam 		if (mlock(Rmtname)) {
34413639Ssam 			omsg('R', "LCK", Ofn);
34513639Ssam 			cleanup(0);
34613639Ssam 		}
34713639Ssam 		else if (callback(Loginuser)) {
34813639Ssam 			signal(SIGINT, SIG_IGN);
34913639Ssam 			signal(SIGHUP, SIG_IGN);
35013639Ssam 			omsg('R', "CB", Ofn);
35113639Ssam 			logent("CALLBACK", "REQUIRED");
35213639Ssam 			/*  set up for call back  */
35317767Sralph 			systat(Rmtname, SS_CALLBACK, "CALLING BACK");
35413639Ssam 			gename(CMDPRE, Rmtname, 'C', file);
35513639Ssam 			close(creat(subfile(file), 0666));
35613639Ssam 			xuucico(Rmtname);
35713639Ssam 			cleanup(0);
35813639Ssam 		}
35913639Ssam 		seq = 0;
36013639Ssam 		while (*p == '-') {
36113639Ssam 			q = pskip(p);
36213639Ssam 			switch(*(++p)) {
36313639Ssam 			case 'x':
36413639Ssam 				Debug = atoi(++p);
36513639Ssam 				if (Debug <= 0)
36613639Ssam 					Debug = 1;
36713639Ssam 				break;
36813639Ssam 			case 'Q':
36913639Ssam 				seq = atoi(++p);
37013639Ssam 				break;
371*18616Sralph 			case 'p':
372*18616Sralph 				MaxGrade = DefMaxGrade = *++p;
373*18616Sralph 				DEBUG(4, "MaxGrade set to %c\n", MaxGrade);
374*18616Sralph 				break;
37513639Ssam 			default:
37613639Ssam 				break;
37713639Ssam 			}
37813639Ssam 			p = q;
37913639Ssam 		}
38013639Ssam 		if (callok(Rmtname) == SS_BADSEQ) {
38113639Ssam 			logent("BADSEQ", "PREVIOUS");
38213639Ssam 			omsg('R', "BADSEQ", Ofn);
38313639Ssam 			cleanup(0);
38413639Ssam 		}
38517767Sralph #ifdef GNXSEQ
38613639Ssam 		if ((ret = gnxseq(Rmtname)) == seq) {
38713639Ssam 			omsg('R', "OK", Ofn);
38813639Ssam 			cmtseq();
38917767Sralph 		} else {
39017767Sralph #else !GNXSEQ
39117767Sralph 		if (seq == 0)
39217767Sralph 			omsg('R', "OK", Ofn);
39313639Ssam 		else {
39417767Sralph #endif !GNXSEQ
39513639Ssam 			systat(Rmtname, Stattype[7], Stattext[7]);
39617767Sralph 			logent("BAD SEQ", "HANDSHAKE FAIL");
39717767Sralph #ifdef GNXSEQ
39813639Ssam 			ulkseq();
39917767Sralph #endif GNXSEQ
40013639Ssam 			omsg('R', "BADSEQ", Ofn);
40113639Ssam 			cleanup(0);
40213639Ssam 		}
40313639Ssam 		ttyn = ttyname(Ifn);
40413639Ssam 		if (ttyn != NULL)
40513639Ssam 			chmod(ttyn, 0600);
40617767Sralph 	} else { /* Role == MASTER */
40717767Sralph 		struct stat stbuf;
40817767Sralph 		if (isatty(fileno(stderr)) || (fstat(fileno(stderr),&stbuf) == 0
40917767Sralph 		    && stbuf.st_mode&S_IFREG) )
41017767Sralph 			StdErrIsTty =  1;
41117767Sralph 		setdebug(0);
41213639Ssam 	}
41317767Sralph 
41413639Ssam loop:
41517767Sralph 	if(setjmp(Pipebuf)) {	/* come here on SIGPIPE	*/
41617767Sralph 		clsacu();
41717767Sralph 		close(Ofn);
41817767Sralph 		close(Ifn);
41917767Sralph 		Ifn = Ofn = -1;
42017767Sralph 		rmlock(CNULL);
42117767Sralph 		sleep(3);
42217767Sralph 	}
42313639Ssam 	if (!onesys) {
42417767Sralph 		struct stat sbuf;
42517767Sralph 
42617767Sralph 		if (!StdErrIsTty) {
42717767Sralph 			sprintf(file, "%s/%s", RMTDEBUG, Rmtname);
42817767Sralph 			if (stat(file, &sbuf) == 0 && sbuf.st_size == 0)
42917767Sralph 				unlink(file);
43017767Sralph 		}
43113639Ssam 		ret = gnsys(Rmtname, Spool, CMDPRE);
43217767Sralph 		setdebug(0);
43313639Ssam 		if (ret == FAIL)
43413639Ssam 			cleanup(100);
43513639Ssam 		if (ret == 0)
43613639Ssam 			cleanup(0);
43717767Sralph 	} else if (Role == MASTER && callok(Rmtname) != 0) {
43813639Ssam 		logent("SYSTEM STATUS", "CAN NOT CALL");
43913639Ssam 		cleanup(0);
44013639Ssam 	}
44113639Ssam 
44213639Ssam 	sprintf(wkpre, "%c.%.7s", CMDPRE, Rmtname);
44313639Ssam 
44417767Sralph 	signal(SIGINT, SIG_IGN);
44517767Sralph 	signal(SIGQUIT, SIG_IGN);
44613639Ssam 	if (Role == MASTER) {
44717767Sralph 		/* check for /etc/nologin */
44817767Sralph 		ultouch();	/* sets nologinflag as a side effect */
44917767Sralph 		if (nologinflag) {
45017767Sralph 			logent(NOLOGIN, "UUCICO SHUTDOWN");
45117767Sralph 			if (Debug)
45217767Sralph 				logent("DEBUGGING", "continuing anyway");
45317767Sralph 			else
45417767Sralph 				cleanup(1);
45517767Sralph 		}
45613639Ssam 		/*  master part */
45713639Ssam 		signal(SIGHUP, SIG_IGN);
458*18616Sralph 		MaxGrade = DefMaxGrade;
45913639Ssam 		if (!iswrk(file, "chk", Spool, wkpre) && !onesys) {
46013639Ssam 			logent(Rmtname, "NO WORK");
46113639Ssam 			goto next;
46213639Ssam 		}
46313639Ssam 		if (Ifn != -1 && Role == MASTER) {
46413639Ssam 			write(Ofn, EOTMSG, strlen(EOTMSG));
46513639Ssam 			clsacu();
46613639Ssam 			close(Ofn);
46713639Ssam 			close(Ifn);
46813639Ssam 			Ifn = Ofn = -1;
46913639Ssam 			rmlock(CNULL);
47013639Ssam 			sleep(3);
47113639Ssam 		}
47213639Ssam 		sprintf(msg, "call to %s ", Rmtname);
47313639Ssam 		if (mlock(Rmtname) != 0) {
47413639Ssam 			logent(msg, "LOCKED");
47517767Sralph 			US_SST(us_s_lock);
47613639Ssam 			goto next;
47713639Ssam 		}
47813639Ssam 		Ofn = Ifn = conn(Rmtname);
47913639Ssam 		if (Ofn < 0) {
48017767Sralph 			if (Ofn != CF_TIME)
48117767Sralph 				logent(msg, _FAILED);
48217767Sralph 			/* avoid excessive 'wrong time' info */
48317767Sralph 			if (Stattype[-Ofn] != SS_WRONGTIME || argv[0][0] != 'U'){
48417767Sralph 				systat(Rmtname, Stattype[-Ofn], Stattext[-Ofn]);
48517767Sralph 				US_SST(-Ofn);
48617767Sralph 				UB_SST(-Ofn);
48717767Sralph 			}
48813639Ssam 			goto next;
48917767Sralph 		} else {
49013639Ssam 			logent(msg, "SUCCEEDED");
49117767Sralph 			US_SST(us_s_cok);
49217767Sralph 			UB_SST(ub_ok);
49313639Ssam 		}
49417767Sralph #ifdef	TCPIP
49517767Sralph 		/*
49617767Sralph 		 * Determine if we are on TCPIP
49717767Sralph 		 */
49817767Sralph 		if (isatty(Ifn) ==  0) {
49917767Sralph 			IsTcpIp = 1;
50017767Sralph 			DEBUG(4, "TCPIP connection -- ioctl-s disabled\n", CNULL);
50117767Sralph 		}
50217767Sralph #endif
50317767Sralph 
50413639Ssam 		if (setjmp(Sjbuf))
50513639Ssam 			goto next;
50613639Ssam 		signal(SIGALRM, timeout);
50713639Ssam 		alarm(2 * MAXMSGTIME);
50813639Ssam 		for (;;) {
50913639Ssam 			ret = imsg(msg, Ifn);
51013639Ssam 			if (ret != 0) {
51113639Ssam 				alarm(0);
51217767Sralph 				logent("imsg 1", _FAILED);
51317767Sralph 				goto Failure;
51413639Ssam 			}
51513639Ssam 			if (msg[0] == 'S')
51613639Ssam 				break;
51713639Ssam 		}
51813639Ssam 		alarm(MAXMSGTIME);
51917767Sralph #ifdef GNXSEQ
52013639Ssam 		seq = gnxseq(Rmtname);
52117767Sralph #else !GNXSEQ
52217767Sralph 		seq = 0;
52317767Sralph #endif !GNXSEQ
524*18616Sralph 		if (MaxGrade != '\177') {
525*18616Sralph 			char buf[10];
526*18616Sralph 			sprintf(buf, " -p%c", MaxGrade);
527*18616Sralph 			strcat(rflags, buf);
528*18616Sralph 		}
529*18616Sralph 
53013639Ssam 		sprintf(msg, "%.7s -Q%d %s", Myname, seq, rflags);
53113639Ssam 		omsg('S', msg, Ofn);
53213639Ssam 		for (;;) {
53313639Ssam 			ret = imsg(msg, Ifn);
53413639Ssam 			DEBUG(4, "msg-%s\n", msg);
53517767Sralph 			if (ret != SUCCESS) {
53613639Ssam 				alarm(0);
53717767Sralph #ifdef GNXSEQ
53813639Ssam 				ulkseq();
53917767Sralph #endif GNXSEQ
54017767Sralph 				logent("imsg 2", _FAILED);
54117767Sralph 				goto Failure;
54213639Ssam 			}
54313639Ssam 			if (msg[0] == 'R')
54413639Ssam 				break;
54513639Ssam 		}
54613639Ssam 		alarm(0);
54713639Ssam 		if (msg[1] == 'B') {
54813639Ssam 			/* bad sequence */
54917767Sralph 			logent("BAD SEQ", "HANDSHAKE FAIL");
55017767Sralph 			US_SST(us_s_hand);
55117767Sralph 			systat(Rmtname, SS_BADSEQ, Stattext[SS_BADSEQ]);
55217767Sralph #ifdef GNXSEQ
55313639Ssam 			ulkseq();
55417767Sralph #endif GNXSEQ
55513639Ssam 			goto next;
55613639Ssam 		}
55713639Ssam 		if (strcmp(&msg[1], "OK") != SAME)  {
55817767Sralph 			logent(&msg[1], "HANDSHAKE FAIL");
55917767Sralph 			US_SST(us_s_hand);
56017767Sralph #ifdef GNXSEQ
56113639Ssam 			ulkseq();
56217767Sralph #endif GNXSEQ
56317767Sralph 			systat(Rmtname, SS_INPROGRESS,
56417767Sralph 				strcmp(&msg[1], "CB") == SAME?
56517767Sralph 				"AWAITING CALLBACK": "HANDSHAKE FAIL");
56613639Ssam 			goto next;
56713639Ssam 		}
56817767Sralph #ifdef GNXSEQ
56913639Ssam 		cmtseq();
57017767Sralph #endif GNXSEQ
57113639Ssam 	}
57217767Sralph 	DEBUG(1, "Rmtname %s, ", Rmtname);
57313639Ssam 	DEBUG(1, "Role %s,  ", Role ? "MASTER" : "SLAVE");
57413639Ssam 	DEBUG(1, "Ifn - %d, ", Ifn);
57513639Ssam 	DEBUG(1, "Loginuser - %s\n", Loginuser);
57613639Ssam 
57713639Ssam 	alarm(MAXMSGTIME);
578*18616Sralph 	if (ret=setjmp(Sjbuf))
57913639Ssam 		goto Failure;
58013639Ssam 	ret = startup(Role);
58113639Ssam 	alarm(0);
58213639Ssam 	if (ret != SUCCESS) {
58317767Sralph 		logent("startup", _FAILED);
58413639Ssam Failure:
58517767Sralph 		US_SST(us_s_start);
586*18616Sralph 		systat(Rmtname, SS_FAIL, ret > 0 ? "CONVERSATION FAILED" :
587*18616Sralph 			"STARTUP FAILED");
58813639Ssam 		goto next;
58917767Sralph 	} else {
59013639Ssam 		logent("startup", "OK");
59117767Sralph 		US_SST(us_s_gress);
59213639Ssam 		systat(Rmtname, SS_INPROGRESS, "TALKING");
59313639Ssam 		ret = cntrl(Role, wkpre);
59413639Ssam 		DEBUG(1, "cntrl - %d\n", ret);
59513639Ssam 		signal(SIGINT, SIG_IGN);
59613639Ssam 		signal(SIGHUP, SIG_IGN);
59713639Ssam 		signal(SIGALRM, timeout);
59817767Sralph 		if (ret == SUCCESS) {
59913639Ssam 			logent("conversation complete", "OK");
60017767Sralph 			US_SST(us_s_ok);
60113639Ssam 			rmstat(Rmtname);
60213639Ssam 
60317767Sralph 		} else {
60417767Sralph 			logent("conversation complete", _FAILED);
60517767Sralph 			US_SST(us_s_cf);
60617767Sralph 			systat(Rmtname, SS_FAIL, "CONVERSATION FAILED");
60713639Ssam 		}
60813639Ssam 		alarm(MAXMSGTIME);
60913639Ssam 		DEBUG(4, "send OO %d,", ret);
61013639Ssam 		if (!setjmp(Sjbuf)) {
61113639Ssam 			for (;;) {
61213639Ssam 				omsg('O', "OOOOO", Ofn);
61313639Ssam 				ret = imsg(msg, Ifn);
61413639Ssam 				if (ret != 0)
61513639Ssam 					break;
61613639Ssam 				if (msg[0] == 'O')
61713639Ssam 					break;
61813639Ssam 			}
61913639Ssam 		}
62013639Ssam 		alarm(0);
62117767Sralph 		clsacu();
62217767Sralph 		rmlock(CNULL);
62313639Ssam 	}
62413639Ssam next:
62513639Ssam 	if (!onesys) {
62613639Ssam 		goto loop;
62713639Ssam 	}
62813639Ssam 	cleanup(0);
62913639Ssam }
63013639Ssam 
63117767Sralph #ifndef	USG
63213639Ssam struct sgttyb Hupvec;
63313639Ssam #endif
63413639Ssam 
63513639Ssam /***
63613639Ssam  *	cleanup(code)	cleanup and exit with "code" status
63713639Ssam  *	int code;
63813639Ssam  */
63913639Ssam 
64013639Ssam cleanup(code)
64113639Ssam register int code;
64213639Ssam {
64313639Ssam 	register int ret;
64413639Ssam 	register char *ttyn;
64517767Sralph 	char bfr[BUFSIZ];
64617767Sralph 	struct stat sbuf;
64713639Ssam 
64813639Ssam 	signal(SIGINT, SIG_IGN);
64913639Ssam 	signal(SIGHUP, SIG_IGN);
65013639Ssam 	rmlock(CNULL);
65113639Ssam 	clsacu();
65213639Ssam 	logcls();
65313639Ssam 	if (Role == SLAVE) {
65417767Sralph 		if (!IsTcpIp) {
65517767Sralph #ifdef USG
65613639Ssam 			Savettyb.c_cflag |= HUPCL;
65713639Ssam 			ret = ioctl(0, TCSETA, &Savettyb);
65817767Sralph #else !USG
65913639Ssam 			ret = ioctl(0, TIOCHPCL, STBNULL);
660*18616Sralph #ifdef TIOCSDTR
661*18616Sralph 			ret = ioctl(0, TIOCCDTR, STBNULL);
662*18616Sralph 			sleep(2);
663*18616Sralph 			ret = ioctl(0, TIOCSDTR, STBNULL);
664*18616Sralph #else !TIOCSDTR
66513639Ssam 			ret = ioctl(0, TIOCGETP, &Hupvec);
666*18616Sralph #endif !TIOCSDTR
66713639Ssam 			Hupvec.sg_ispeed = B0;
66813639Ssam 			Hupvec.sg_ospeed = B0;
66913639Ssam 			ret = ioctl(0, TIOCSETP, &Hupvec);
67013639Ssam 			sleep(2);
67113639Ssam 			ret = ioctl(0, TIOCSETP, &Savettyb);
67217767Sralph 			/* make *sure* exclusive access is off */
67317767Sralph 			ret = ioctl(0, TIOCNXCL, STBNULL);
67417767Sralph #endif !USG
67513639Ssam 			DEBUG(4, "ret ioctl - %d\n", ret);
67613639Ssam 		}
67713639Ssam 		ttyn = ttyname(Ifn);
67813639Ssam 		if (ttyn != NULL)
67913639Ssam 			chmod(ttyn, 0600);
68013639Ssam 	}
68113639Ssam 	if (Ofn != -1) {
68213639Ssam 		if (Role == MASTER)
68313639Ssam 			write(Ofn, EOTMSG, strlen(EOTMSG));
68413639Ssam 		close(Ifn);
68513639Ssam 		close(Ofn);
68613639Ssam 	}
687*18616Sralph #ifdef DIALINOUT
688*18616Sralph 	/* reenable logins on dialout */
689*18616Sralph 	reenable();
690*18616Sralph #endif DIALINOUT
69113639Ssam 	if (code == 0)
69213639Ssam 		xuuxqt();
69317767Sralph 	else
69417767Sralph 		DEBUG(1, "exit code %d\n", code);
69517767Sralph 	sprintf(bfr, "%s/%s", RMTDEBUG, Rmtname);
69617767Sralph 	if (stat(bfr, &sbuf) == 0 && sbuf.st_size == 0)
69717767Sralph 		unlink(bfr);
69817767Sralph 	sprintf(bfr, "%s/%d", RMTDEBUG, getpid());
69917767Sralph 	unlink(bfr);
70013639Ssam 	exit(code);
70113639Ssam }
70213639Ssam 
70313639Ssam /***
70413639Ssam  *	onintr(inter)	interrupt - remove locks and exit
70513639Ssam  */
70613639Ssam 
70713639Ssam onintr(inter)
70813639Ssam register int inter;
70913639Ssam {
71013639Ssam 	char str[30];
71113639Ssam 	signal(inter, SIG_IGN);
71213639Ssam 	sprintf(str, "SIGNAL %d", inter);
71313639Ssam 	logent(str, "CAUGHT");
71417767Sralph 	US_SST(us_s_intr);
715*18616Sralph 	if (*Rmtname && strncmp(Rmtname, Myname, 7))
71617767Sralph 		systat(Rmtname, SS_FAIL, str);
71717767Sralph 	if (inter == SIGPIPE && !onesys)
71817767Sralph 		longjmp(Pipebuf, 1);
71913639Ssam 	cleanup(inter);
72013639Ssam }
72113639Ssam 
72213639Ssam /*
72313639Ssam  * Catch a special signal
72413639Ssam  * (SIGFPE, ugh), and toggle debugging between 0 and 30.
72513639Ssam  * Handy for looking in on long running uucicos.
72613639Ssam  */
72717767Sralph setdebug(code)
72817767Sralph int code;
72913639Ssam {
73017767Sralph 	char buf[BUFSIZ];
73117767Sralph 
73217767Sralph 	if (!StdErrIsTty) {
73317767Sralph 		sprintf(buf,"%s/%s", RMTDEBUG, Rmtname);
73417767Sralph 		unlink(buf);
73517767Sralph 		freopen(buf, "w", stderr);
73617767Sralph #ifdef BSD4_2
73717767Sralph 		setlinebuf(stderr);
73817767Sralph #else  !BSD4_2
73917767Sralph 		setbuf(stderr, NULL);
74017767Sralph #endif !BSD4_2
74117767Sralph 	}
74217767Sralph 	if (code) {
74317767Sralph 		if (Debug == 0)
74417767Sralph 			Debug = 30;
74517767Sralph 		else
74617767Sralph 			Debug = 0;
74717767Sralph 	}
74813639Ssam }
74913639Ssam 
75013639Ssam 
75113639Ssam /***
75213639Ssam  *	fixmode(tty)	fix kill/echo/raw on line
75313639Ssam  *
75413639Ssam  *	return codes:  none
75513639Ssam  */
75613639Ssam 
75713639Ssam fixmode(tty)
75813639Ssam register int tty;
75913639Ssam {
76017767Sralph #ifdef	USG
76113639Ssam 	struct termio ttbuf;
76213639Ssam #endif
76317767Sralph #ifndef	USG
76413639Ssam 	struct sgttyb ttbuf;
76513639Ssam #endif
76613639Ssam 	register int ret;
76713639Ssam 
76817767Sralph 	if (IsTcpIp)
76913639Ssam 		return;
77017767Sralph #ifdef	USG
77117767Sralph 	ret = ioctl(tty, TCGETA, &ttbuf);
77213639Ssam 	ttbuf.c_iflag = ttbuf.c_oflag = ttbuf.c_lflag = (ushort)0;
77313639Ssam 	ttbuf.c_cflag &= (CBAUD);
77413639Ssam 	ttbuf.c_cflag |= (CS8|CREAD);
77513639Ssam 	ttbuf.c_cc[VMIN] = 6;
77613639Ssam 	ttbuf.c_cc[VTIME] = 1;
77713639Ssam 	ret = ioctl(tty, TCSETA, &ttbuf);
77813639Ssam #endif
77917767Sralph #ifndef	USG
78013639Ssam 	ioctl(tty, TIOCGETP, &ttbuf);
78113639Ssam 	ttbuf.sg_flags = (ANYP | RAW);
78213639Ssam 	ret = ioctl(tty, TIOCSETP, &ttbuf);
78313639Ssam #endif
78417767Sralph /*	ASSERT(ret >= 0, "STTY FAILED", CNULL, ret); */
78517767Sralph #ifndef	USG
78617767Sralph 	ret = ioctl(tty, TIOCEXCL, STBNULL);
78713639Ssam #endif
78813639Ssam }
78913639Ssam 
79013639Ssam 
79113639Ssam /***
79213639Ssam  *	timeout()	catch SIGALRM routine
79313639Ssam  */
79413639Ssam 
79513639Ssam timeout()
79613639Ssam {
79713639Ssam 	logent(Rmtname, "TIMEOUT");
798*18616Sralph 	if (*Rmtname && strncmp(Rmtname, Myname, 7)) {
79917767Sralph 		US_SST(us_s_tmot);
80017767Sralph 		systat(Rmtname, SS_FAIL, "TIMEOUT");
80117767Sralph 	}
80213639Ssam 	longjmp(Sjbuf, 1);
80313639Ssam }
80413639Ssam 
80513639Ssam static char *
80613639Ssam pskip(p)
80713639Ssam register char *p;
80813639Ssam {
80917767Sralph 	while(*p && *p != ' ')
81013639Ssam 		++p;
81117767Sralph 	if(*p)
81217767Sralph 		*p++ = 0;
81317767Sralph 	return p;
81413639Ssam }
815