xref: /csrg-svn/usr.bin/uucp/uucico/cico.c (revision 26149)
113639Ssam #ifndef lint
2*26149Sbloom static char sccsid[] = "@(#)cico.c	5.13 (Berkeley) 02/12/86";
313639Ssam #endif
413639Ssam 
523590Sbloom #include <signal.h>
613639Ssam #include "uucp.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 
2323590Sbloom #if defined(VMS) && defined(BSDTCP)
2423590Sbloom #define NOGETPEER
2523590Sbloom #endif
2623590Sbloom 
2723590Sbloom #ifdef BSD2_9
2823590Sbloom #define NOGETPEER
2923590Sbloom #endif
3023590Sbloom 
3117767Sralph jmp_buf Sjbuf;
3217767Sralph jmp_buf Pipebuf;
3313639Ssam 
3417767Sralph /*  call fail text  */
3513639Ssam char *Stattext[] = {
3613639Ssam 	"",
3713639Ssam 	"BAD SYSTEM",
3817767Sralph 	"WRONG TIME TO CALL",
3913639Ssam 	"SYSTEM LOCKED",
4013639Ssam 	"NO DEVICE",
4125703Sbloom 	"CALL FAILED",
4213639Ssam 	"LOGIN FAILED",
4313639Ssam 	"BAD SEQUENCE"
4417767Sralph };
4513639Ssam 
4617767Sralph /*  call fail codes  */
4717767Sralph int Stattype[] = {
4817767Sralph 	0,
4917767Sralph 	0,
5017767Sralph 	SS_WRONGTIME,
5117767Sralph 	0,
5217767Sralph 	SS_NODEVICE,
5317767Sralph 	SS_FAIL,
5417767Sralph 	SS_FAIL,
5517767Sralph 	SS_BADSEQ
5617767Sralph };
5713639Ssam 
5825703Sbloom 				/* Arguments to setdebug():		     */
5925703Sbloom #define DBG_TEMP  0		/*   Create a temporary audit file	     */
6025703Sbloom #define DBG_PERM  1		/*   Create a permanent audit file	     */
6125703Sbloom #define DBG_CLEAN 2		/*   Cleanup, discard temp file		     */
6213639Ssam 
6317767Sralph int ReverseRole = 0;
6417767Sralph int Role = SLAVE;
6517767Sralph int onesys = 0;
6618616Sralph int turntime = 30 * 60;	/* 30 minutes expressed in seconds */
6725703Sbloom char *ttyn = NULL;
6817767Sralph extern int LocalOnly;
6925703Sbloom extern int errno;
7018616Sralph extern char MaxGrade, DefMaxGrade;
7118616Sralph extern char Myfullname[];
7217767Sralph 
7317767Sralph #ifdef	USG
7413639Ssam struct termio Savettyb;
7513639Ssam #endif
7617767Sralph #ifndef	USG
7713639Ssam struct sgttyb Savettyb;
7813639Ssam #endif
7913639Ssam 
8025703Sbloom /*
8125703Sbloom  *	this program is used  to place a call to a
8213639Ssam  *	remote machine, login, and copy files between the two machines.
8313639Ssam  */
8413639Ssam main(argc, argv)
8525703Sbloom int argc;
8613639Ssam register char *argv[];
8713639Ssam {
8813639Ssam 	register int ret;
8913639Ssam 	int seq;
9013639Ssam 	char wkpre[NAMESIZE], file[NAMESIZE];
9125703Sbloom 	char msg[MAXFULLNAME], *q;
9213639Ssam 	register char *p;
9325703Sbloom 	extern onintr(), timeout(), dbg_signal();
9413639Ssam 	extern char *pskip();
9523725Sbloom 	char rflags[MAXFULLNAME];
9623590Sbloom #ifdef NOGETPEER
9717767Sralph 	u_long Hostnumber = 0;
9823590Sbloom #endif NOGETPEER
9913639Ssam 
10013639Ssam 	strcpy(Progname, "uucico");
10113639Ssam 
102*26149Sbloom #ifdef BSD4_2
103*26149Sbloom 	sigsetmask(0);	/* in case we inherit blocked signals */
104*26149Sbloom #endif BSD4_2
10513639Ssam 	signal(SIGINT, onintr);
10613639Ssam 	signal(SIGHUP, onintr);
10713639Ssam 	signal(SIGQUIT, onintr);
10813639Ssam 	signal(SIGTERM, onintr);
10913639Ssam 	signal(SIGPIPE, onintr);	/* 4.1a tcp-ip stupidity */
11025703Sbloom 	signal(SIGFPE, dbg_signal);
11113639Ssam 	ret = guinfo(getuid(), User, msg);
11213639Ssam 	strcpy(Loginuser, User);
11323590Sbloom 	uucpname(Myname);
11417767Sralph 	ASSERT(ret == 0, "BAD UID", CNULL, ret);
11513639Ssam 
11625703Sbloom 	setbuf (stderr, CNULL);
11725703Sbloom 
11825703Sbloom 	rflags[0] = '\0';
11913639Ssam 	umask(WFMASK);
12013639Ssam 	strcpy(Rmtname, Myname);
12113639Ssam 	Ifn = Ofn = -1;
12213639Ssam 	while(argc>1 && argv[1][0] == '-'){
12313639Ssam 		switch(argv[1][1]){
12413639Ssam 		case 'd':
12513639Ssam 			Spool = &argv[1][2];
12613639Ssam 			break;
12713639Ssam 		case 'g':
12818616Sralph 		case 'p':
12918616Sralph 			MaxGrade = DefMaxGrade = argv[1][2];
13013639Ssam 			break;
13113639Ssam 		case 'r':
13213639Ssam 			Role = atoi(&argv[1][2]);
13313639Ssam 			break;
13417767Sralph 		case 'R':
13517767Sralph 			ReverseRole++;
13617767Sralph 			Role = MASTER;
13717767Sralph 			break;
13813639Ssam 		case 's':
13923590Sbloom 			strncpy(Rmtname, &argv[1][2], MAXBASENAME);
14023590Sbloom 			Rmtname[MAXBASENAME] = '\0';
14113639Ssam 			if (Rmtname[0] != '\0')
14213639Ssam 				onesys = 1;
14313639Ssam 			break;
14413639Ssam 		case 'x':
14513639Ssam 			Debug = atoi(&argv[1][2]);
14613639Ssam 			if (Debug <= 0)
14713639Ssam 				Debug = 1;
14825703Sbloom 			strcat(rflags, argv[1]);
14913639Ssam 			break;
15018616Sralph 		case 't':
15118616Sralph 			turntime = atoi(&argv[1][2])*60;/* minutes to seconds */
15218616Sralph 			break;
15317767Sralph 		case 'L':	/* local calls only */
15417767Sralph 			LocalOnly++;
15517767Sralph 			break;
15623590Sbloom #ifdef NOGETPEER
15717767Sralph 		case 'h':
15817767Sralph 			Hostnumber = inet_addr(&argv[1][2]);
15917767Sralph 			break;
16023590Sbloom #endif NOGETPEER
16113639Ssam 		default:
16217767Sralph 			printf("unknown flag %s (ignored)\n", argv[1]);
16313639Ssam 			break;
16413639Ssam 		}
16513639Ssam 		--argc;  argv++;
16613639Ssam 	}
16713639Ssam 
16817767Sralph 	while (argc > 1) {
16925703Sbloom 		fprintf(stderr, "unknown argument %s (ignored)\n", argv[1]);
17017767Sralph 		--argc; argv++;
17117767Sralph 	}
17217767Sralph 
17325124Sbloom 	/* Try to run as uucp */
17417767Sralph 	setgid(getegid());
17517767Sralph 	setuid(geteuid());
17617767Sralph #ifdef	TIOCNOTTY
17717767Sralph 	/*
17817767Sralph 	 * detach uucico from controlling terminal
17917767Sralph 	 * to defend against rlogind sending us a SIGKILL (!!!)
18017767Sralph 	 */
18117767Sralph 	if (Role == MASTER && (ret = open("/dev/tty", 2)) >= 0) {
18217767Sralph 		ioctl(ret, TIOCNOTTY, STBNULL);
18317767Sralph 		close(ret);
18417767Sralph 	}
18517767Sralph #endif TIOCNOTTY
18617767Sralph #ifdef BSD4_2
18725517Stef 	if (getpgrp(0) == 0) { /* We have no controlling terminal */
18817767Sralph 		setpgrp(0, getpid());
18917767Sralph 	}
19017767Sralph #endif BSD4_2
19117767Sralph 
19217767Sralph 	ret = subchdir(Spool);
19317767Sralph 	ASSERT(ret >= 0, "CHDIR FAILED", Spool, ret);
19413639Ssam 	strcpy(Wrkdir, Spool);
19513639Ssam 
19625703Sbloom 	if (Debug) {
19725703Sbloom 		if (Role == MASTER)
19825703Sbloom 			chkdebug();
19925703Sbloom 		setdebug ((Role == SLAVE) ? DBG_TEMP : DBG_PERM);
20025703Sbloom 		if (Debug > 0)
20125703Sbloom 			logent ("Local Enabled", "DEBUG");
20225703Sbloom 	}
20325703Sbloom 
20425703Sbloom 	/*
20525703Sbloom 	 * First time through: If we're the slave, do initial checking.
20625703Sbloom 	 */
20713639Ssam 	if (Role == SLAVE) {
20817767Sralph 		/* check for /etc/nologin */
20925124Sbloom 		if (access(NOLOGIN, 0) == 0) {
21017767Sralph 			logent(NOLOGIN, "UUCICO SHUTDOWN");
21123590Sbloom 			if (Debug > 4)
21217767Sralph 				logent("DEBUGGING", "continuing anyway");
21317767Sralph 			else
21417767Sralph 				cleanup(1);
21517767Sralph 		}
21625703Sbloom 		Ifn = 0;
21725703Sbloom 		Ofn = 1;
21817767Sralph #ifdef	TCPIP
21917767Sralph 		/*
22017767Sralph 		 * Determine if we are on TCPIP
22117767Sralph 		 */
22225703Sbloom 		if (isatty(Ifn) < 0) {
22317767Sralph 			IsTcpIp = 1;
22417767Sralph 			DEBUG(4, "TCPIP connection -- ioctl-s disabled\n", CNULL);
22523590Sbloom 		} else
22623590Sbloom 			IsTcpIp = 0;
22717767Sralph #endif TCPIP
22813639Ssam 		/* initial handshake */
22913639Ssam 		onesys = 1;
23017767Sralph 		if (!IsTcpIp) {
23117767Sralph #ifdef	USG
23225703Sbloom 			ret = ioctl(Ifn, TCGETA, &Savettyb);
23313639Ssam 			Savettyb.c_cflag = (Savettyb.c_cflag & ~CS8) | CS7;
23413639Ssam 			Savettyb.c_oflag |= OPOST;
23513639Ssam 			Savettyb.c_lflag |= (ISIG|ICANON|ECHO);
23617767Sralph #else !USG
23725703Sbloom 			ret = ioctl(Ifn, TIOCGETP, &Savettyb);
23813639Ssam 			Savettyb.sg_flags |= ECHO;
23913639Ssam 			Savettyb.sg_flags &= ~RAW;
24017767Sralph #endif !USG
24125703Sbloom 			ttyn = ttyname(Ifn);
24213639Ssam 		}
24313639Ssam 		fixmode(Ifn);
24425703Sbloom 
24525703Sbloom 		/*
24625703Sbloom 		 * Initial Message -- tell them we're here, and who we are.
24725703Sbloom 		 */
24818616Sralph 		sprintf(msg, "here=%s", Myfullname);
24917767Sralph 		omsg('S', msg, Ofn);
25013639Ssam 		signal(SIGALRM, timeout);
25113639Ssam 		alarm(MAXMSGTIME);
25213639Ssam 		if (setjmp(Sjbuf)) {
25313639Ssam 			/* timed out */
25417767Sralph 			if (!IsTcpIp) {
25517767Sralph #ifdef	USG
25625703Sbloom 				ret = ioctl(Ifn, TCSETA, &Savettyb);
25725703Sbloom 
25823590Sbloom #else	!USG
25925703Sbloom 				ret = ioctl(Ifn, TIOCSETP, &Savettyb);
26023590Sbloom #endif !USG
26113639Ssam 			}
26217767Sralph 			cleanup(0);
26313639Ssam 		}
26413639Ssam 		for (;;) {
26513639Ssam 			ret = imsg(msg, Ifn);
26625703Sbloom 			if (ret != SUCCESS) {
26713639Ssam 				alarm(0);
26817767Sralph 				if (!IsTcpIp) {
26917767Sralph #ifdef	USG
27025703Sbloom 					ret = ioctl(Ifn, TCSETA, &Savettyb);
27123590Sbloom #else	!USG
27225703Sbloom 					ret = ioctl(Ifn, TIOCSETP, &Savettyb);
27323590Sbloom #endif !USG
27413639Ssam 				}
27517767Sralph 				cleanup(0);
27613639Ssam 			}
27713639Ssam 			if (msg[0] == 'S')
27813639Ssam 				break;
27913639Ssam 		}
28013639Ssam 		alarm(0);
28113639Ssam 		q = &msg[1];
28213639Ssam 		p = pskip(q);
28323590Sbloom 		strncpy(Rmtname, q, MAXBASENAME);
28423590Sbloom 		Rmtname[MAXBASENAME] = '\0';
28525703Sbloom 
28625703Sbloom 		/*
28725703Sbloom 		 * Now that we know who they are, give the audit file the right
28825703Sbloom 		 * name.
28925703Sbloom 		 */
29025703Sbloom 		setdebug (DBG_PERM);
29113639Ssam 		DEBUG(4, "sys-%s\n", Rmtname);
29223725Sbloom 		/* The versys will also do an alias on the incoming name */
29323725Sbloom 		if (versys(&Rmtname)) {
29423725Sbloom 			/* If we don't know them, we won't talk to them... */
29523590Sbloom #ifdef	NOSTRANGERS
29623590Sbloom 			logent(Rmtname, "UNKNOWN HOST");
29723590Sbloom 			omsg('R', "You are unknown to me", Ofn);
29823590Sbloom 			cleanup(0);
29923725Sbloom #endif	NOSTRANGERS
30023590Sbloom 		}
30117767Sralph #ifdef BSDTCP
30217767Sralph 		/* we must make sure they are really who they say they
30317767Sralph 		 * are. We compare the hostnumber with the number in the hosts
30417767Sralph 		 * table for the site they claim to be.
30517767Sralph 		 */
30617767Sralph 		if (IsTcpIp) {
30717767Sralph 			struct hostent *hp;
30817767Sralph 			char *cpnt, *inet_ntoa();
30925703Sbloom 			int fromlen;
31017767Sralph 			struct sockaddr_in from;
31125124Sbloom 			extern char PhoneNumber[];
31217767Sralph 
31323590Sbloom #ifdef	NOGETPEER
31423590Sbloom 			from.sin_addr.s_addr = Hostnumber;
31523590Sbloom 			from.sin_family = AF_INET;
31623590Sbloom #else	!NOGETPEER
31725703Sbloom 			fromlen = sizeof(from);
31825703Sbloom 			if (getpeername(Ifn, &from, &fromlen) < 0) {
31917767Sralph 				logent(Rmtname, "NOT A TCP CONNECTION");
32017767Sralph 				omsg('R', "NOT TCP", Ofn);
32117767Sralph 				cleanup(0);
32217767Sralph 			}
32323590Sbloom #endif	!NOGETPEER
32417767Sralph 			hp = gethostbyaddr(&from.sin_addr,
32517767Sralph 				sizeof (struct in_addr), from.sin_family);
32625703Sbloom 			if (hp == NULL) {
32717767Sralph 				/* security break or just old host table? */
32817767Sralph 				logent(Rmtname, "UNKNOWN IP-HOST Name =");
32917767Sralph 				cpnt = inet_ntoa(from.sin_addr),
33017767Sralph 				logent(cpnt, "UNKNOWN IP-HOST Number =");
33117767Sralph 				sprintf(wkpre, "%s/%s isn't in my host table",
33217767Sralph 					Rmtname, cpnt);
33317767Sralph 				omsg('R' ,wkpre ,Ofn);
33417767Sralph 				cleanup(0);
33517767Sralph 			}
33625703Sbloom 			if (Debug > 99)
33717767Sralph 				logent(Rmtname,"Request from IP-Host name =");
33825124Sbloom 			/*
33925124Sbloom 			 * The following is to determine if the name given us by
34025124Sbloom 			 * the Remote uucico matches any of the names
34117767Sralph 			 * given its network number (remote machine) in our
34217767Sralph 			 * host table.
34325124Sbloom 			 * We could check the aliases, but that won't work in
34425124Sbloom 			 * all cases (like if you are running the domain
34525124Sbloom 			 * server, where you don't get any aliases). The only
34625124Sbloom 			 * reliable way I can think of that works in ALL cases
34725124Sbloom 			 * is too look up the site in L.sys and see if the
34825124Sbloom 			 * sitename matches what we would call him if we
34925124Sbloom 			 * originated the call.
35017767Sralph 			 */
35125124Sbloom 			/* PhoneNumber contains the official network name of the 			   host we are checking. (set in versys.c) */
35225124Sbloom 			if (sncncmp(PhoneNumber, hp->h_name, SYSNSIZE) == 0) {
35317767Sralph 				if (Debug > 99)
35417767Sralph 					logent(q,"Found in host Tables");
35525124Sbloom 			} else {
35625124Sbloom 				logent(hp->h_name, "FORGED HOSTNAME");
35725124Sbloom 				logent(inet_ntoa(from.sin_addr), "ORIGINATED AT");
35825124Sbloom 				logent(PhoneNumber, "SHOULD BE");
35925124Sbloom 				sprintf(wkpre, "You're not who you claim to be: %s !=  %s", hp->h_name, PhoneNumber);
36025124Sbloom 				omsg('R', wkpre, Ofn);
36125124Sbloom 				cleanup(0);
36217767Sralph 			}
36317767Sralph 		}
36417767Sralph #endif	BSDTCP
36517767Sralph 
36625703Sbloom 		if (mlock(Rmtname)) {
36713639Ssam 			omsg('R', "LCK", Ofn);
36813639Ssam 			cleanup(0);
36913639Ssam 		}
37013639Ssam 		else if (callback(Loginuser)) {
37113639Ssam 			signal(SIGINT, SIG_IGN);
37213639Ssam 			signal(SIGHUP, SIG_IGN);
37313639Ssam 			omsg('R', "CB", Ofn);
37413639Ssam 			logent("CALLBACK", "REQUIRED");
37513639Ssam 			/*  set up for call back  */
37617767Sralph 			systat(Rmtname, SS_CALLBACK, "CALLING BACK");
37713639Ssam 			gename(CMDPRE, Rmtname, 'C', file);
37813639Ssam 			close(creat(subfile(file), 0666));
37913639Ssam 			xuucico(Rmtname);
38013639Ssam 			cleanup(0);
38113639Ssam 		}
38213639Ssam 		seq = 0;
38313639Ssam 		while (*p == '-') {
38413639Ssam 			q = pskip(p);
38513639Ssam 			switch(*(++p)) {
38613639Ssam 			case 'x':
38725703Sbloom 				if (Debug == 0) {
38825703Sbloom 					Debug = atoi(++p);
38925703Sbloom 					if (Debug <= 0)
39025703Sbloom 						Debug = 1;
39125703Sbloom 					setdebug(DBG_PERM);
39225703Sbloom 					if (Debug > 0)
39325703Sbloom 						logent("Remote Enabled", "DEBUG");
39425703Sbloom 				} else {
39525703Sbloom 					DEBUG(1, "Remote debug request ignored\n",
39625703Sbloom 					   CNULL);
39725703Sbloom 				}
39813639Ssam 				break;
39913639Ssam 			case 'Q':
40013639Ssam 				seq = atoi(++p);
40113639Ssam 				break;
40218616Sralph 			case 'p':
40318616Sralph 				MaxGrade = DefMaxGrade = *++p;
40418616Sralph 				DEBUG(4, "MaxGrade set to %c\n", MaxGrade);
40518616Sralph 				break;
40623590Sbloom 			case 'v':
40723590Sbloom 				if (strncmp(p, "grade", 5) == 0) {
40823590Sbloom 					p += 6;
40923590Sbloom 					MaxGrade = DefMaxGrade = *p++;
41023590Sbloom 					DEBUG(4, "MaxGrade set to %c\n", MaxGrade);
41123590Sbloom 				}
41223590Sbloom 				break;
41313639Ssam 			default:
41413639Ssam 				break;
41513639Ssam 			}
41613639Ssam 			p = q;
41713639Ssam 		}
41813639Ssam 		if (callok(Rmtname) == SS_BADSEQ) {
41913639Ssam 			logent("BADSEQ", "PREVIOUS");
42013639Ssam 			omsg('R', "BADSEQ", Ofn);
42113639Ssam 			cleanup(0);
42213639Ssam 		}
42317767Sralph #ifdef GNXSEQ
42413639Ssam 		if ((ret = gnxseq(Rmtname)) == seq) {
42513639Ssam 			omsg('R', "OK", Ofn);
42613639Ssam 			cmtseq();
42717767Sralph 		} else {
42817767Sralph #else !GNXSEQ
42917767Sralph 		if (seq == 0)
43017767Sralph 			omsg('R', "OK", Ofn);
43113639Ssam 		else {
43217767Sralph #endif !GNXSEQ
43313639Ssam 			systat(Rmtname, Stattype[7], Stattext[7]);
43423590Sbloom 			logent("BAD SEQ", "FAILED HANDSHAKE");
43517767Sralph #ifdef GNXSEQ
43613639Ssam 			ulkseq();
43717767Sralph #endif GNXSEQ
43813639Ssam 			omsg('R', "BADSEQ", Ofn);
43913639Ssam 			cleanup(0);
44013639Ssam 		}
44113639Ssam 		if (ttyn != NULL)
44213639Ssam 			chmod(ttyn, 0600);
44313639Ssam 	}
44417767Sralph 
44513639Ssam loop:
44617767Sralph 	if(setjmp(Pipebuf)) {	/* come here on SIGPIPE	*/
44717767Sralph 		clsacu();
44817767Sralph 		close(Ofn);
44917767Sralph 		close(Ifn);
45017767Sralph 		Ifn = Ofn = -1;
45117767Sralph 		rmlock(CNULL);
45217767Sralph 		sleep(3);
45317767Sralph 	}
45413639Ssam 	if (!onesys) {
45513639Ssam 		ret = gnsys(Rmtname, Spool, CMDPRE);
45625703Sbloom 		setdebug(DBG_PERM);
45713639Ssam 		if (ret == FAIL)
45813639Ssam 			cleanup(100);
45923590Sbloom 		if (ret == SUCCESS)
46013639Ssam 			cleanup(0);
46117767Sralph 	} else if (Role == MASTER && callok(Rmtname) != 0) {
46213639Ssam 		logent("SYSTEM STATUS", "CAN NOT CALL");
46313639Ssam 		cleanup(0);
46413639Ssam 	}
46513639Ssam 
46623590Sbloom 	sprintf(wkpre, "%c.%.*s", CMDPRE, SYSNSIZE, Rmtname);
46713639Ssam 
46817767Sralph 	signal(SIGINT, SIG_IGN);
46917767Sralph 	signal(SIGQUIT, SIG_IGN);
47013639Ssam 	if (Role == MASTER) {
47117767Sralph 		/* check for /etc/nologin */
47225124Sbloom 		if (access(NOLOGIN, 0) == 0) {
47317767Sralph 			logent(NOLOGIN, "UUCICO SHUTDOWN");
47423590Sbloom 			if (Debug > 4)
47517767Sralph 				logent("DEBUGGING", "continuing anyway");
47617767Sralph 			else
47717767Sralph 				cleanup(1);
47817767Sralph 		}
47913639Ssam 		/*  master part */
48013639Ssam 		signal(SIGHUP, SIG_IGN);
48113639Ssam 		if (Ifn != -1 && Role == MASTER) {
48213639Ssam 			write(Ofn, EOTMSG, strlen(EOTMSG));
48313639Ssam 			clsacu();
48413639Ssam 			close(Ofn);
48513639Ssam 			close(Ifn);
48613639Ssam 			Ifn = Ofn = -1;
48713639Ssam 			rmlock(CNULL);
48813639Ssam 			sleep(3);
48913639Ssam 		}
49013639Ssam 		sprintf(msg, "call to %s ", Rmtname);
49125124Sbloom 		if (mlock(Rmtname) != SUCCESS) {
49213639Ssam 			logent(msg, "LOCKED");
49317767Sralph 			US_SST(us_s_lock);
49413639Ssam 			goto next;
49513639Ssam 		}
49613639Ssam 		Ofn = Ifn = conn(Rmtname);
49713639Ssam 		if (Ofn < 0) {
49817767Sralph 			if (Ofn != CF_TIME)
49917767Sralph 				logent(msg, _FAILED);
50017767Sralph 			/* avoid excessive 'wrong time' info */
50123590Sbloom 			if (Stattype[-Ofn] != SS_WRONGTIME){
50217767Sralph 				systat(Rmtname, Stattype[-Ofn], Stattext[-Ofn]);
50317767Sralph 				US_SST(-Ofn);
50417767Sralph 				UB_SST(-Ofn);
50517767Sralph 			}
50613639Ssam 			goto next;
50717767Sralph 		} else {
50813639Ssam 			logent(msg, "SUCCEEDED");
50917767Sralph 			US_SST(us_s_cok);
51017767Sralph 			UB_SST(ub_ok);
51113639Ssam 		}
51217767Sralph #ifdef	TCPIP
51317767Sralph 		/*
51417767Sralph 		 * Determine if we are on TCPIP
51517767Sralph 		 */
51625703Sbloom 		if (isatty(Ifn) == 0) {
51717767Sralph 			IsTcpIp = 1;
51817767Sralph 			DEBUG(4, "TCPIP connection -- ioctl-s disabled\n", CNULL);
51923590Sbloom 		} else
52023590Sbloom 			IsTcpIp = 0;
52117767Sralph #endif
52217767Sralph 
52313639Ssam 		if (setjmp(Sjbuf))
52413639Ssam 			goto next;
52513639Ssam 		signal(SIGALRM, timeout);
52613639Ssam 		alarm(2 * MAXMSGTIME);
52713639Ssam 		for (;;) {
52813639Ssam 			ret = imsg(msg, Ifn);
52913639Ssam 			if (ret != 0) {
53013639Ssam 				alarm(0);
53117767Sralph 				logent("imsg 1", _FAILED);
53217767Sralph 				goto Failure;
53313639Ssam 			}
53413639Ssam 			if (msg[0] == 'S')
53513639Ssam 				break;
53613639Ssam 		}
53713639Ssam 		alarm(MAXMSGTIME);
53817767Sralph #ifdef GNXSEQ
53913639Ssam 		seq = gnxseq(Rmtname);
54017767Sralph #else !GNXSEQ
54117767Sralph 		seq = 0;
54217767Sralph #endif !GNXSEQ
54318616Sralph 		if (MaxGrade != '\177') {
54423590Sbloom 			DEBUG(2, "Max Grade this transfer is %c\n", MaxGrade);
54525963Sbloom 			sprintf(msg, "%s -Q%d -p%c -vgrade=%c %s",
54625963Sbloom 				Myname, seq, MaxGrade, MaxGrade, rflags);
54725963Sbloom 		} else
54825963Sbloom 			sprintf(msg, "%s -Q%d %s", Myname, seq, rflags);
54913639Ssam 		omsg('S', msg, Ofn);
55013639Ssam 		for (;;) {
55113639Ssam 			ret = imsg(msg, Ifn);
55213639Ssam 			DEBUG(4, "msg-%s\n", msg);
55317767Sralph 			if (ret != SUCCESS) {
55413639Ssam 				alarm(0);
55517767Sralph #ifdef GNXSEQ
55613639Ssam 				ulkseq();
55717767Sralph #endif GNXSEQ
55817767Sralph 				logent("imsg 2", _FAILED);
55917767Sralph 				goto Failure;
56013639Ssam 			}
56113639Ssam 			if (msg[0] == 'R')
56213639Ssam 				break;
56313639Ssam 		}
56413639Ssam 		alarm(0);
56513639Ssam 		if (msg[1] == 'B') {
56613639Ssam 			/* bad sequence */
56723590Sbloom 			logent("BAD SEQ", "FAILED HANDSHAKE");
56817767Sralph 			US_SST(us_s_hand);
56917767Sralph 			systat(Rmtname, SS_BADSEQ, Stattext[SS_BADSEQ]);
57017767Sralph #ifdef GNXSEQ
57113639Ssam 			ulkseq();
57217767Sralph #endif GNXSEQ
57313639Ssam 			goto next;
57413639Ssam 		}
57513639Ssam 		if (strcmp(&msg[1], "OK") != SAME)  {
57623590Sbloom 			logent(&msg[1], "FAILED HANDSHAKE");
57717767Sralph 			US_SST(us_s_hand);
57817767Sralph #ifdef GNXSEQ
57913639Ssam 			ulkseq();
58017767Sralph #endif GNXSEQ
58117767Sralph 			systat(Rmtname, SS_INPROGRESS,
58217767Sralph 				strcmp(&msg[1], "CB") == SAME?
58323590Sbloom 				"AWAITING CALLBACK": "FAILED HANDSHAKE");
58413639Ssam 			goto next;
58513639Ssam 		}
58617767Sralph #ifdef GNXSEQ
58713639Ssam 		cmtseq();
58817767Sralph #endif GNXSEQ
58913639Ssam 	}
59017767Sralph 	DEBUG(1, "Rmtname %s, ", Rmtname);
59113639Ssam 	DEBUG(1, "Role %s,  ", Role ? "MASTER" : "SLAVE");
59213639Ssam 	DEBUG(1, "Ifn - %d, ", Ifn);
59313639Ssam 	DEBUG(1, "Loginuser - %s\n", Loginuser);
59413639Ssam 
59525703Sbloom 	ttyn = ttyname(Ifn);
59625703Sbloom 
59713639Ssam 	alarm(MAXMSGTIME);
59818616Sralph 	if (ret=setjmp(Sjbuf))
59913639Ssam 		goto Failure;
60013639Ssam 	ret = startup(Role);
60113639Ssam 	alarm(0);
60213639Ssam 	if (ret != SUCCESS) {
60317767Sralph 		logent("startup", _FAILED);
60413639Ssam Failure:
60517767Sralph 		US_SST(us_s_start);
60618616Sralph 		systat(Rmtname, SS_FAIL, ret > 0 ? "CONVERSATION FAILED" :
60718616Sralph 			"STARTUP FAILED");
60813639Ssam 		goto next;
60917767Sralph 	} else {
61025703Sbloom 		if (ttyn != NULL) {
61125703Sbloom 			char startupmsg[BUFSIZ];
61225703Sbloom 			extern int linebaudrate;
61325703Sbloom 			sprintf(startupmsg, "startup %s %d baud", &ttyn[5],
61425703Sbloom 				linebaudrate);
61525703Sbloom 			logent(startupmsg, "OK");
61625703Sbloom 		} else
61725703Sbloom 			logent("startup", "OK");
61817767Sralph 		US_SST(us_s_gress);
61913639Ssam 		systat(Rmtname, SS_INPROGRESS, "TALKING");
62013639Ssam 		ret = cntrl(Role, wkpre);
62113639Ssam 		DEBUG(1, "cntrl - %d\n", ret);
62213639Ssam 		signal(SIGINT, SIG_IGN);
62313639Ssam 		signal(SIGHUP, SIG_IGN);
62413639Ssam 		signal(SIGALRM, timeout);
62517767Sralph 		if (ret == SUCCESS) {
62613639Ssam 			logent("conversation complete", "OK");
62717767Sralph 			US_SST(us_s_ok);
62813639Ssam 			rmstat(Rmtname);
62913639Ssam 
63017767Sralph 		} else {
63117767Sralph 			logent("conversation complete", _FAILED);
63217767Sralph 			US_SST(us_s_cf);
63317767Sralph 			systat(Rmtname, SS_FAIL, "CONVERSATION FAILED");
63413639Ssam 		}
63513639Ssam 		alarm(MAXMSGTIME);
63613639Ssam 		DEBUG(4, "send OO %d,", ret);
63713639Ssam 		if (!setjmp(Sjbuf)) {
63813639Ssam 			for (;;) {
63913639Ssam 				omsg('O', "OOOOO", Ofn);
64013639Ssam 				ret = imsg(msg, Ifn);
64113639Ssam 				if (ret != 0)
64213639Ssam 					break;
64313639Ssam 				if (msg[0] == 'O')
64413639Ssam 					break;
64513639Ssam 			}
64613639Ssam 		}
64713639Ssam 		alarm(0);
64817767Sralph 		clsacu();
64917767Sralph 		rmlock(CNULL);
65013639Ssam 	}
65113639Ssam next:
65213639Ssam 	if (!onesys) {
65313639Ssam 		goto loop;
65413639Ssam 	}
65513639Ssam 	cleanup(0);
65613639Ssam }
65713639Ssam 
65817767Sralph #ifndef	USG
65913639Ssam struct sgttyb Hupvec;
66013639Ssam #endif
66113639Ssam 
66225703Sbloom /*
66325703Sbloom  *	cleanup and exit with "code" status
66413639Ssam  */
66513639Ssam cleanup(code)
66613639Ssam register int code;
66713639Ssam {
66813639Ssam 	signal(SIGINT, SIG_IGN);
66913639Ssam 	signal(SIGHUP, SIG_IGN);
67013639Ssam 	rmlock(CNULL);
67125703Sbloom 	sleep(5);			/* Wait for any pending output	  */
67213639Ssam 	clsacu();
67313639Ssam 	logcls();
67413639Ssam 	if (Role == SLAVE) {
67517767Sralph 		if (!IsTcpIp) {
67617767Sralph #ifdef USG
67713639Ssam 			Savettyb.c_cflag |= HUPCL;
67823590Sbloom 			(void) ioctl(0, TCSETA, &Savettyb);
67917767Sralph #else !USG
68023590Sbloom 			(void) ioctl(0, TIOCHPCL, STBNULL);
68118616Sralph #ifdef TIOCSDTR
68223590Sbloom 			(void) ioctl(0, TIOCCDTR, STBNULL);
68318616Sralph 			sleep(2);
68423590Sbloom 			(void) ioctl(0, TIOCSDTR, STBNULL);
68518616Sralph #else !TIOCSDTR
68623590Sbloom 			(void) ioctl(0, TIOCGETP, &Hupvec);
68713639Ssam 			Hupvec.sg_ispeed = B0;
68813639Ssam 			Hupvec.sg_ospeed = B0;
68923590Sbloom 			(void) ioctl(0, TIOCSETP, &Hupvec);
69025703Sbloom #endif !TIOCSDTR
69113639Ssam 			sleep(2);
69223590Sbloom 			(void) ioctl(0, TIOCSETP, &Savettyb);
69317767Sralph 			/* make *sure* exclusive access is off */
69423590Sbloom 			(void) ioctl(0, TIOCNXCL, STBNULL);
69517767Sralph #endif !USG
69613639Ssam 		}
69713639Ssam 		if (ttyn != NULL)
69813639Ssam 			chmod(ttyn, 0600);
69913639Ssam 	}
70013639Ssam 	if (Ofn != -1) {
70113639Ssam 		if (Role == MASTER)
70213639Ssam 			write(Ofn, EOTMSG, strlen(EOTMSG));
70313639Ssam 		close(Ifn);
70413639Ssam 		close(Ofn);
70513639Ssam 	}
70618616Sralph #ifdef DIALINOUT
70718616Sralph 	/* reenable logins on dialout */
70818616Sralph 	reenable();
70918616Sralph #endif DIALINOUT
71013639Ssam 	if (code == 0)
71113639Ssam 		xuuxqt();
71217767Sralph 	else
71317767Sralph 		DEBUG(1, "exit code %d\n", code);
71425703Sbloom 	setdebug (DBG_CLEAN);
71513639Ssam 	exit(code);
71613639Ssam }
71713639Ssam 
71825703Sbloom /*
71925703Sbloom  *	on interrupt - remove locks and exit
72013639Ssam  */
72113639Ssam 
72213639Ssam onintr(inter)
72313639Ssam register int inter;
72413639Ssam {
72513639Ssam 	char str[30];
72613639Ssam 	signal(inter, SIG_IGN);
72713639Ssam 	sprintf(str, "SIGNAL %d", inter);
72813639Ssam 	logent(str, "CAUGHT");
72917767Sralph 	US_SST(us_s_intr);
73023590Sbloom 	if (*Rmtname && strncmp(Rmtname, Myname, MAXBASENAME))
73117767Sralph 		systat(Rmtname, SS_FAIL, str);
73217767Sralph 	if (inter == SIGPIPE && !onesys)
73317767Sralph 		longjmp(Pipebuf, 1);
73413639Ssam 	cleanup(inter);
73513639Ssam }
73613639Ssam 
73713639Ssam /*
73813639Ssam  * Catch a special signal
73913639Ssam  * (SIGFPE, ugh), and toggle debugging between 0 and 30.
74013639Ssam  * Handy for looking in on long running uucicos.
74113639Ssam  */
74225703Sbloom dbg_signal()
74313639Ssam {
74425703Sbloom 	Debug = (Debug == 0) ? 30 : 0;
74525703Sbloom 	setdebug(DBG_PERM);
74625703Sbloom 	if (Debug > 0)
74725703Sbloom 		logent("Signal Enabled", "DEBUG");
74825703Sbloom }
74917767Sralph 
75025703Sbloom 
75125703Sbloom /*
75225703Sbloom  * Check debugging requests, and open RMTDEBUG audit file if necessary. If an
75325703Sbloom  * audit file is needed, the parm argument indicates how to create the file:
75425703Sbloom  *
75525703Sbloom  *	DBG_TEMP  - Open a temporary file, with filename = RMTDEBUG/pid.
75625703Sbloom  *	DBG_PERM  - Open a permanent audit file, filename = RMTDEBUG/Rmtname.
75725703Sbloom  *		    If a temp file already exists, it is mv'ed to be permanent.
75825703Sbloom  *	DBG_CLEAN - Cleanup; unlink temp files.
75925703Sbloom  *
76025703Sbloom  * Restrictions - this code can only cope with one open debug file at a time.
76125703Sbloom  * Each call creates a new file; if an old one of the same name exists it will
76225703Sbloom  * be overwritten.
76325703Sbloom  */
76425703Sbloom setdebug(parm)
76525703Sbloom int parm;
76625703Sbloom {
76725703Sbloom 	char buf[BUFSIZ];		/* Buffer for building filenames     */
76825703Sbloom 	static char *temp = NULL;	/* Ptr to temporary file name	     */
76925703Sbloom 	static int auditopen = 0;	/* Set to 1 when we open a file	     */
77025703Sbloom 	struct stat stbuf;		/* File status buffer		     */
77125703Sbloom 
77225703Sbloom 	/*
77325703Sbloom 	 * If movement or cleanup of a temp file is indicated, we do it no
77425703Sbloom 	 * matter what.
77525703Sbloom 	 */
77625703Sbloom 	if (temp != CNULL && parm == DBG_PERM) {
77725703Sbloom 		sprintf(buf, "%s/%s", RMTDEBUG, Rmtname);
77825703Sbloom 		unlink(buf);
77925703Sbloom 		if (link(temp, buf) != 0) {
78023590Sbloom 			Debug = 0;
78125703Sbloom 			assert("RMTDEBUG LINK FAIL", temp, errno);
78225703Sbloom 			cleanup(1);
78325703Sbloom 		}
78425703Sbloom 		parm = DBG_CLEAN;
78523590Sbloom 	}
78625703Sbloom 	if (parm == DBG_CLEAN) {
78725703Sbloom 		if (temp != CNULL) {
78825703Sbloom 			unlink(temp);
78925703Sbloom 			free(temp);
79025703Sbloom 			temp = CNULL;
79125703Sbloom 		}
79225703Sbloom 		return;
79325703Sbloom 	}
79425703Sbloom 
79525703Sbloom 	if (Debug == 0)
79625703Sbloom 		return;		/* Gotta be in debug to come here.   */
79725703Sbloom 
79825703Sbloom 	/*
79925703Sbloom 	 * If we haven't opened a file already, we can just return if it's
80025703Sbloom 	 * alright to use the stderr we came in with. We can if:
80125703Sbloom 	 *
80225703Sbloom 	 *	Role == MASTER, and Stderr is a regular file, a TTY or a pipe.
80325703Sbloom 	 *
80425703Sbloom 	 * Caution: Detecting when stderr is a pipe is tricky, because the 4.2
80525703Sbloom 	 * man page for fstat(2) disagrees with reality, and System V leaves it
80625703Sbloom 	 * undefined, which means different implementations act differently.
80725703Sbloom 	 */
80825703Sbloom 	if (!auditopen && Role == MASTER) {
80925703Sbloom 		if (isatty(fileno(stderr)))
81025703Sbloom 			return;
81125703Sbloom 		else if (fstat(fileno(stderr), &stbuf) == 0) {
81225703Sbloom #ifdef USG
81325703Sbloom 			/* Is Regular File or Fifo   */
81425703Sbloom 			if ((stbuf.st_mode & 0060000) == 0)
81525703Sbloom 				return;
81625703Sbloom #else !USG
81717767Sralph #ifdef BSD4_2
81825703Sbloom 					/* Is Regular File */
81925703Sbloom 			if ((stbuf.st_mode & S_IFMT) == S_IFREG ||
82025703Sbloom 			    stbuf.st_mode == 0)		/* Is a pipe */
82125703Sbloom 				return;
82225703Sbloom #else !BSD4_2
82325703Sbloom 					 /* Is Regular File or Pipe  */
82425703Sbloom 			if ((stbuf.st_mode & S_IFMT) == S_IFREG)
82525703Sbloom 				return;
82625703Sbloom #endif BSD4_2
82725703Sbloom #endif USG
82825703Sbloom 		}
82917767Sralph 	}
83013639Ssam 
83125703Sbloom 	/*
83225703Sbloom 	 * We need RMTDEBUG directory to do auditing. If the file doesn't exist,
83325703Sbloom 	 * then we forget about debugging; if it exists but has improper owner-
83425703Sbloom 	 * ship or modes, we gripe about it in ERRLOG.
83525703Sbloom 	 */
83625703Sbloom 	if (stat(RMTDEBUG, &stbuf) != SUCCESS) {
83725703Sbloom 		Debug = 0;
83825703Sbloom 		return;
83925703Sbloom 	}
84025703Sbloom 	if ((geteuid() != stbuf.st_uid) ||	  	/* We must own it    */
84125703Sbloom 	    ((stbuf.st_mode & 0170700) != 040700)) {	/* Directory, rwx    */
84225703Sbloom 		Debug = 0;
84325703Sbloom 		assert("INVALID RMTDEBUG DIRECTORY:", RMTDEBUG, stbuf.st_mode);
84425703Sbloom 		return;
84525703Sbloom 	}
84613639Ssam 
84725703Sbloom 	if (parm == DBG_TEMP) {
84825703Sbloom 		sprintf(buf, "%s/%d", RMTDEBUG, getpid());
84925703Sbloom 		temp = malloc(strlen (buf) + 1);
85025703Sbloom 		if (temp == CNULL) {
85125703Sbloom 			Debug = 0;
85225703Sbloom 			assert("RMTDEBUG MALLOC ERROR:", temp, errno);
85325703Sbloom 			cleanup(1);
85425703Sbloom 		}
85525703Sbloom 		strcpy(temp, buf);
85625703Sbloom 	} else
85725703Sbloom 		sprintf(buf, "%s/%s", RMTDEBUG, Rmtname);
85813639Ssam 
85925703Sbloom 	unlink(buf);
86025703Sbloom 	if (freopen(buf, "w", stderr) != stderr) {
86125703Sbloom 		Debug = 0;
86225703Sbloom 		assert("FAILED RMTDEBUG FILE OPEN:", buf, errno);
86325703Sbloom 		cleanup(1);
86425703Sbloom 	}
86525703Sbloom 	setbuf(stderr, CNULL);
86625703Sbloom 	auditopen = 1;
86713639Ssam }
86813639Ssam 
86923590Sbloom /*
87025703Sbloom  *	catch SIGALRM routine
87113639Ssam  */
87213639Ssam timeout()
87313639Ssam {
87423590Sbloom 	extern int HaveSentHup;
87523590Sbloom 	if (!HaveSentHup) {
87623590Sbloom 		logent(Rmtname, "TIMEOUT");
87723590Sbloom 		if (*Rmtname && strncmp(Rmtname, Myname, MAXBASENAME)) {
87823590Sbloom 			US_SST(us_s_tmot);
87923590Sbloom 			systat(Rmtname, SS_FAIL, "TIMEOUT");
88023590Sbloom 		}
88117767Sralph 	}
88213639Ssam 	longjmp(Sjbuf, 1);
88313639Ssam }
88413639Ssam 
88513639Ssam static char *
88613639Ssam pskip(p)
88713639Ssam register char *p;
88813639Ssam {
88917767Sralph 	while(*p && *p != ' ')
89013639Ssam 		++p;
89123590Sbloom 	while(*p && *p == ' ')
89217767Sralph 		*p++ = 0;
89317767Sralph 	return p;
89413639Ssam }
895