xref: /csrg-svn/usr.bin/uucp/uucico/cico.c (revision 27069)
113639Ssam #ifndef lint
2*27069Sbloom static char sccsid[] = "@(#)cico.c	5.14 (Berkeley) 04/14/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 
10226149Sbloom #ifdef BSD4_2
10326149Sbloom 	sigsetmask(0);	/* in case we inherit blocked signals */
10426149Sbloom #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 
173*27069Sbloom 	if (Debug && Role == MASTER)
174*27069Sbloom 		chkdebug();
175*27069Sbloom 
17625124Sbloom 	/* Try to run as uucp */
17717767Sralph 	setgid(getegid());
17817767Sralph 	setuid(geteuid());
17917767Sralph #ifdef	TIOCNOTTY
18017767Sralph 	/*
18117767Sralph 	 * detach uucico from controlling terminal
18217767Sralph 	 * to defend against rlogind sending us a SIGKILL (!!!)
18317767Sralph 	 */
18417767Sralph 	if (Role == MASTER && (ret = open("/dev/tty", 2)) >= 0) {
18517767Sralph 		ioctl(ret, TIOCNOTTY, STBNULL);
18617767Sralph 		close(ret);
18717767Sralph 	}
18817767Sralph #endif TIOCNOTTY
18917767Sralph #ifdef BSD4_2
19025517Stef 	if (getpgrp(0) == 0) { /* We have no controlling terminal */
19117767Sralph 		setpgrp(0, getpid());
19217767Sralph 	}
19317767Sralph #endif BSD4_2
19417767Sralph 
19517767Sralph 	ret = subchdir(Spool);
19617767Sralph 	ASSERT(ret >= 0, "CHDIR FAILED", Spool, ret);
19713639Ssam 	strcpy(Wrkdir, Spool);
19813639Ssam 
19925703Sbloom 	if (Debug) {
20025703Sbloom 		setdebug ((Role == SLAVE) ? DBG_TEMP : DBG_PERM);
20125703Sbloom 		if (Debug > 0)
20225703Sbloom 			logent ("Local Enabled", "DEBUG");
20325703Sbloom 	}
20425703Sbloom 
20525703Sbloom 	/*
20625703Sbloom 	 * First time through: If we're the slave, do initial checking.
20725703Sbloom 	 */
20813639Ssam 	if (Role == SLAVE) {
20917767Sralph 		/* check for /etc/nologin */
21025124Sbloom 		if (access(NOLOGIN, 0) == 0) {
21117767Sralph 			logent(NOLOGIN, "UUCICO SHUTDOWN");
21223590Sbloom 			if (Debug > 4)
21317767Sralph 				logent("DEBUGGING", "continuing anyway");
21417767Sralph 			else
21517767Sralph 				cleanup(1);
21617767Sralph 		}
21725703Sbloom 		Ifn = 0;
21825703Sbloom 		Ofn = 1;
21917767Sralph #ifdef	TCPIP
22017767Sralph 		/*
22117767Sralph 		 * Determine if we are on TCPIP
22217767Sralph 		 */
22325703Sbloom 		if (isatty(Ifn) < 0) {
22417767Sralph 			IsTcpIp = 1;
22517767Sralph 			DEBUG(4, "TCPIP connection -- ioctl-s disabled\n", CNULL);
22623590Sbloom 		} else
22723590Sbloom 			IsTcpIp = 0;
22817767Sralph #endif TCPIP
22913639Ssam 		/* initial handshake */
23013639Ssam 		onesys = 1;
23117767Sralph 		if (!IsTcpIp) {
23217767Sralph #ifdef	USG
23325703Sbloom 			ret = ioctl(Ifn, TCGETA, &Savettyb);
23413639Ssam 			Savettyb.c_cflag = (Savettyb.c_cflag & ~CS8) | CS7;
23513639Ssam 			Savettyb.c_oflag |= OPOST;
23613639Ssam 			Savettyb.c_lflag |= (ISIG|ICANON|ECHO);
23717767Sralph #else !USG
23825703Sbloom 			ret = ioctl(Ifn, TIOCGETP, &Savettyb);
23913639Ssam 			Savettyb.sg_flags |= ECHO;
24013639Ssam 			Savettyb.sg_flags &= ~RAW;
24117767Sralph #endif !USG
24225703Sbloom 			ttyn = ttyname(Ifn);
24313639Ssam 		}
24413639Ssam 		fixmode(Ifn);
24525703Sbloom 
24625703Sbloom 		/*
24725703Sbloom 		 * Initial Message -- tell them we're here, and who we are.
24825703Sbloom 		 */
24918616Sralph 		sprintf(msg, "here=%s", Myfullname);
25017767Sralph 		omsg('S', msg, Ofn);
25113639Ssam 		signal(SIGALRM, timeout);
25213639Ssam 		alarm(MAXMSGTIME);
25313639Ssam 		if (setjmp(Sjbuf)) {
25413639Ssam 			/* timed out */
25517767Sralph 			if (!IsTcpIp) {
25617767Sralph #ifdef	USG
25725703Sbloom 				ret = ioctl(Ifn, TCSETA, &Savettyb);
25825703Sbloom 
25923590Sbloom #else	!USG
26025703Sbloom 				ret = ioctl(Ifn, TIOCSETP, &Savettyb);
26123590Sbloom #endif !USG
26213639Ssam 			}
26317767Sralph 			cleanup(0);
26413639Ssam 		}
26513639Ssam 		for (;;) {
26613639Ssam 			ret = imsg(msg, Ifn);
26725703Sbloom 			if (ret != SUCCESS) {
26813639Ssam 				alarm(0);
26917767Sralph 				if (!IsTcpIp) {
27017767Sralph #ifdef	USG
27125703Sbloom 					ret = ioctl(Ifn, TCSETA, &Savettyb);
27223590Sbloom #else	!USG
27325703Sbloom 					ret = ioctl(Ifn, TIOCSETP, &Savettyb);
27423590Sbloom #endif !USG
27513639Ssam 				}
27617767Sralph 				cleanup(0);
27713639Ssam 			}
27813639Ssam 			if (msg[0] == 'S')
27913639Ssam 				break;
28013639Ssam 		}
28113639Ssam 		alarm(0);
28213639Ssam 		q = &msg[1];
28313639Ssam 		p = pskip(q);
28423590Sbloom 		strncpy(Rmtname, q, MAXBASENAME);
28523590Sbloom 		Rmtname[MAXBASENAME] = '\0';
28625703Sbloom 
28725703Sbloom 		/*
28825703Sbloom 		 * Now that we know who they are, give the audit file the right
28925703Sbloom 		 * name.
29025703Sbloom 		 */
29125703Sbloom 		setdebug (DBG_PERM);
29213639Ssam 		DEBUG(4, "sys-%s\n", Rmtname);
29323725Sbloom 		/* The versys will also do an alias on the incoming name */
29423725Sbloom 		if (versys(&Rmtname)) {
29523725Sbloom 			/* If we don't know them, we won't talk to them... */
29623590Sbloom #ifdef	NOSTRANGERS
29723590Sbloom 			logent(Rmtname, "UNKNOWN HOST");
29823590Sbloom 			omsg('R', "You are unknown to me", Ofn);
29923590Sbloom 			cleanup(0);
30023725Sbloom #endif	NOSTRANGERS
30123590Sbloom 		}
30217767Sralph #ifdef BSDTCP
30317767Sralph 		/* we must make sure they are really who they say they
30417767Sralph 		 * are. We compare the hostnumber with the number in the hosts
30517767Sralph 		 * table for the site they claim to be.
30617767Sralph 		 */
30717767Sralph 		if (IsTcpIp) {
30817767Sralph 			struct hostent *hp;
30917767Sralph 			char *cpnt, *inet_ntoa();
31025703Sbloom 			int fromlen;
31117767Sralph 			struct sockaddr_in from;
31225124Sbloom 			extern char PhoneNumber[];
31317767Sralph 
31423590Sbloom #ifdef	NOGETPEER
31523590Sbloom 			from.sin_addr.s_addr = Hostnumber;
31623590Sbloom 			from.sin_family = AF_INET;
31723590Sbloom #else	!NOGETPEER
31825703Sbloom 			fromlen = sizeof(from);
31925703Sbloom 			if (getpeername(Ifn, &from, &fromlen) < 0) {
32017767Sralph 				logent(Rmtname, "NOT A TCP CONNECTION");
32117767Sralph 				omsg('R', "NOT TCP", Ofn);
32217767Sralph 				cleanup(0);
32317767Sralph 			}
32423590Sbloom #endif	!NOGETPEER
32517767Sralph 			hp = gethostbyaddr(&from.sin_addr,
32617767Sralph 				sizeof (struct in_addr), from.sin_family);
32725703Sbloom 			if (hp == NULL) {
32817767Sralph 				/* security break or just old host table? */
32917767Sralph 				logent(Rmtname, "UNKNOWN IP-HOST Name =");
33017767Sralph 				cpnt = inet_ntoa(from.sin_addr),
33117767Sralph 				logent(cpnt, "UNKNOWN IP-HOST Number =");
33217767Sralph 				sprintf(wkpre, "%s/%s isn't in my host table",
33317767Sralph 					Rmtname, cpnt);
33417767Sralph 				omsg('R' ,wkpre ,Ofn);
33517767Sralph 				cleanup(0);
33617767Sralph 			}
33725703Sbloom 			if (Debug > 99)
33817767Sralph 				logent(Rmtname,"Request from IP-Host name =");
33925124Sbloom 			/*
34025124Sbloom 			 * The following is to determine if the name given us by
34125124Sbloom 			 * the Remote uucico matches any of the names
34217767Sralph 			 * given its network number (remote machine) in our
34317767Sralph 			 * host table.
34425124Sbloom 			 * We could check the aliases, but that won't work in
34525124Sbloom 			 * all cases (like if you are running the domain
34625124Sbloom 			 * server, where you don't get any aliases). The only
34725124Sbloom 			 * reliable way I can think of that works in ALL cases
34825124Sbloom 			 * is too look up the site in L.sys and see if the
34925124Sbloom 			 * sitename matches what we would call him if we
35025124Sbloom 			 * originated the call.
35117767Sralph 			 */
35225124Sbloom 			/* PhoneNumber contains the official network name of the 			   host we are checking. (set in versys.c) */
35325124Sbloom 			if (sncncmp(PhoneNumber, hp->h_name, SYSNSIZE) == 0) {
35417767Sralph 				if (Debug > 99)
35517767Sralph 					logent(q,"Found in host Tables");
35625124Sbloom 			} else {
35725124Sbloom 				logent(hp->h_name, "FORGED HOSTNAME");
35825124Sbloom 				logent(inet_ntoa(from.sin_addr), "ORIGINATED AT");
35925124Sbloom 				logent(PhoneNumber, "SHOULD BE");
36025124Sbloom 				sprintf(wkpre, "You're not who you claim to be: %s !=  %s", hp->h_name, PhoneNumber);
36125124Sbloom 				omsg('R', wkpre, Ofn);
36225124Sbloom 				cleanup(0);
36317767Sralph 			}
36417767Sralph 		}
36517767Sralph #endif	BSDTCP
36617767Sralph 
36725703Sbloom 		if (mlock(Rmtname)) {
36813639Ssam 			omsg('R', "LCK", Ofn);
36913639Ssam 			cleanup(0);
37013639Ssam 		}
37113639Ssam 		else if (callback(Loginuser)) {
37213639Ssam 			signal(SIGINT, SIG_IGN);
37313639Ssam 			signal(SIGHUP, SIG_IGN);
37413639Ssam 			omsg('R', "CB", Ofn);
37513639Ssam 			logent("CALLBACK", "REQUIRED");
37613639Ssam 			/*  set up for call back  */
37717767Sralph 			systat(Rmtname, SS_CALLBACK, "CALLING BACK");
37813639Ssam 			gename(CMDPRE, Rmtname, 'C', file);
37913639Ssam 			close(creat(subfile(file), 0666));
38013639Ssam 			xuucico(Rmtname);
38113639Ssam 			cleanup(0);
38213639Ssam 		}
38313639Ssam 		seq = 0;
38413639Ssam 		while (*p == '-') {
38513639Ssam 			q = pskip(p);
38613639Ssam 			switch(*(++p)) {
38713639Ssam 			case 'x':
38825703Sbloom 				if (Debug == 0) {
38925703Sbloom 					Debug = atoi(++p);
39025703Sbloom 					if (Debug <= 0)
39125703Sbloom 						Debug = 1;
39225703Sbloom 					setdebug(DBG_PERM);
39325703Sbloom 					if (Debug > 0)
39425703Sbloom 						logent("Remote Enabled", "DEBUG");
39525703Sbloom 				} else {
39625703Sbloom 					DEBUG(1, "Remote debug request ignored\n",
39725703Sbloom 					   CNULL);
39825703Sbloom 				}
39913639Ssam 				break;
40013639Ssam 			case 'Q':
40113639Ssam 				seq = atoi(++p);
40213639Ssam 				break;
40318616Sralph 			case 'p':
40418616Sralph 				MaxGrade = DefMaxGrade = *++p;
40518616Sralph 				DEBUG(4, "MaxGrade set to %c\n", MaxGrade);
40618616Sralph 				break;
40723590Sbloom 			case 'v':
40823590Sbloom 				if (strncmp(p, "grade", 5) == 0) {
40923590Sbloom 					p += 6;
41023590Sbloom 					MaxGrade = DefMaxGrade = *p++;
41123590Sbloom 					DEBUG(4, "MaxGrade set to %c\n", MaxGrade);
41223590Sbloom 				}
41323590Sbloom 				break;
41413639Ssam 			default:
41513639Ssam 				break;
41613639Ssam 			}
41713639Ssam 			p = q;
41813639Ssam 		}
41913639Ssam 		if (callok(Rmtname) == SS_BADSEQ) {
42013639Ssam 			logent("BADSEQ", "PREVIOUS");
42113639Ssam 			omsg('R', "BADSEQ", Ofn);
42213639Ssam 			cleanup(0);
42313639Ssam 		}
42417767Sralph #ifdef GNXSEQ
42513639Ssam 		if ((ret = gnxseq(Rmtname)) == seq) {
42613639Ssam 			omsg('R', "OK", Ofn);
42713639Ssam 			cmtseq();
42817767Sralph 		} else {
42917767Sralph #else !GNXSEQ
43017767Sralph 		if (seq == 0)
43117767Sralph 			omsg('R', "OK", Ofn);
43213639Ssam 		else {
43317767Sralph #endif !GNXSEQ
43413639Ssam 			systat(Rmtname, Stattype[7], Stattext[7]);
43523590Sbloom 			logent("BAD SEQ", "FAILED HANDSHAKE");
43617767Sralph #ifdef GNXSEQ
43713639Ssam 			ulkseq();
43817767Sralph #endif GNXSEQ
43913639Ssam 			omsg('R', "BADSEQ", Ofn);
44013639Ssam 			cleanup(0);
44113639Ssam 		}
44213639Ssam 		if (ttyn != NULL)
44313639Ssam 			chmod(ttyn, 0600);
44413639Ssam 	}
44517767Sralph 
44613639Ssam loop:
44717767Sralph 	if(setjmp(Pipebuf)) {	/* come here on SIGPIPE	*/
44817767Sralph 		clsacu();
44917767Sralph 		close(Ofn);
45017767Sralph 		close(Ifn);
45117767Sralph 		Ifn = Ofn = -1;
45217767Sralph 		rmlock(CNULL);
45317767Sralph 		sleep(3);
45417767Sralph 	}
45513639Ssam 	if (!onesys) {
45613639Ssam 		ret = gnsys(Rmtname, Spool, CMDPRE);
45725703Sbloom 		setdebug(DBG_PERM);
45813639Ssam 		if (ret == FAIL)
45913639Ssam 			cleanup(100);
46023590Sbloom 		if (ret == SUCCESS)
46113639Ssam 			cleanup(0);
46217767Sralph 	} else if (Role == MASTER && callok(Rmtname) != 0) {
46313639Ssam 		logent("SYSTEM STATUS", "CAN NOT CALL");
46413639Ssam 		cleanup(0);
46513639Ssam 	}
46613639Ssam 
46723590Sbloom 	sprintf(wkpre, "%c.%.*s", CMDPRE, SYSNSIZE, Rmtname);
46813639Ssam 
46917767Sralph 	signal(SIGINT, SIG_IGN);
47017767Sralph 	signal(SIGQUIT, SIG_IGN);
47113639Ssam 	if (Role == MASTER) {
47217767Sralph 		/* check for /etc/nologin */
47325124Sbloom 		if (access(NOLOGIN, 0) == 0) {
47417767Sralph 			logent(NOLOGIN, "UUCICO SHUTDOWN");
47523590Sbloom 			if (Debug > 4)
47617767Sralph 				logent("DEBUGGING", "continuing anyway");
47717767Sralph 			else
47817767Sralph 				cleanup(1);
47917767Sralph 		}
48013639Ssam 		/*  master part */
48113639Ssam 		signal(SIGHUP, SIG_IGN);
48213639Ssam 		if (Ifn != -1 && Role == MASTER) {
48313639Ssam 			write(Ofn, EOTMSG, strlen(EOTMSG));
48413639Ssam 			clsacu();
48513639Ssam 			close(Ofn);
48613639Ssam 			close(Ifn);
48713639Ssam 			Ifn = Ofn = -1;
48813639Ssam 			rmlock(CNULL);
48913639Ssam 			sleep(3);
49013639Ssam 		}
49113639Ssam 		sprintf(msg, "call to %s ", Rmtname);
49225124Sbloom 		if (mlock(Rmtname) != SUCCESS) {
49313639Ssam 			logent(msg, "LOCKED");
49417767Sralph 			US_SST(us_s_lock);
49513639Ssam 			goto next;
49613639Ssam 		}
49713639Ssam 		Ofn = Ifn = conn(Rmtname);
49813639Ssam 		if (Ofn < 0) {
49917767Sralph 			if (Ofn != CF_TIME)
50017767Sralph 				logent(msg, _FAILED);
50117767Sralph 			/* avoid excessive 'wrong time' info */
50223590Sbloom 			if (Stattype[-Ofn] != SS_WRONGTIME){
50317767Sralph 				systat(Rmtname, Stattype[-Ofn], Stattext[-Ofn]);
50417767Sralph 				US_SST(-Ofn);
50517767Sralph 				UB_SST(-Ofn);
50617767Sralph 			}
50713639Ssam 			goto next;
50817767Sralph 		} else {
50913639Ssam 			logent(msg, "SUCCEEDED");
51017767Sralph 			US_SST(us_s_cok);
51117767Sralph 			UB_SST(ub_ok);
51213639Ssam 		}
51317767Sralph #ifdef	TCPIP
51417767Sralph 		/*
51517767Sralph 		 * Determine if we are on TCPIP
51617767Sralph 		 */
51725703Sbloom 		if (isatty(Ifn) == 0) {
51817767Sralph 			IsTcpIp = 1;
51917767Sralph 			DEBUG(4, "TCPIP connection -- ioctl-s disabled\n", CNULL);
52023590Sbloom 		} else
52123590Sbloom 			IsTcpIp = 0;
52217767Sralph #endif
52317767Sralph 
52413639Ssam 		if (setjmp(Sjbuf))
52513639Ssam 			goto next;
52613639Ssam 		signal(SIGALRM, timeout);
52713639Ssam 		alarm(2 * MAXMSGTIME);
52813639Ssam 		for (;;) {
52913639Ssam 			ret = imsg(msg, Ifn);
53013639Ssam 			if (ret != 0) {
53113639Ssam 				alarm(0);
53217767Sralph 				logent("imsg 1", _FAILED);
53317767Sralph 				goto Failure;
53413639Ssam 			}
53513639Ssam 			if (msg[0] == 'S')
53613639Ssam 				break;
53713639Ssam 		}
53813639Ssam 		alarm(MAXMSGTIME);
53917767Sralph #ifdef GNXSEQ
54013639Ssam 		seq = gnxseq(Rmtname);
54117767Sralph #else !GNXSEQ
54217767Sralph 		seq = 0;
54317767Sralph #endif !GNXSEQ
54418616Sralph 		if (MaxGrade != '\177') {
54523590Sbloom 			DEBUG(2, "Max Grade this transfer is %c\n", MaxGrade);
54625963Sbloom 			sprintf(msg, "%s -Q%d -p%c -vgrade=%c %s",
54725963Sbloom 				Myname, seq, MaxGrade, MaxGrade, rflags);
54825963Sbloom 		} else
54925963Sbloom 			sprintf(msg, "%s -Q%d %s", Myname, seq, rflags);
55013639Ssam 		omsg('S', msg, Ofn);
55113639Ssam 		for (;;) {
55213639Ssam 			ret = imsg(msg, Ifn);
55313639Ssam 			DEBUG(4, "msg-%s\n", msg);
55417767Sralph 			if (ret != SUCCESS) {
55513639Ssam 				alarm(0);
55617767Sralph #ifdef GNXSEQ
55713639Ssam 				ulkseq();
55817767Sralph #endif GNXSEQ
55917767Sralph 				logent("imsg 2", _FAILED);
56017767Sralph 				goto Failure;
56113639Ssam 			}
56213639Ssam 			if (msg[0] == 'R')
56313639Ssam 				break;
56413639Ssam 		}
56513639Ssam 		alarm(0);
56613639Ssam 		if (msg[1] == 'B') {
56713639Ssam 			/* bad sequence */
56823590Sbloom 			logent("BAD SEQ", "FAILED HANDSHAKE");
56917767Sralph 			US_SST(us_s_hand);
57017767Sralph 			systat(Rmtname, SS_BADSEQ, Stattext[SS_BADSEQ]);
57117767Sralph #ifdef GNXSEQ
57213639Ssam 			ulkseq();
57317767Sralph #endif GNXSEQ
57413639Ssam 			goto next;
57513639Ssam 		}
57613639Ssam 		if (strcmp(&msg[1], "OK") != SAME)  {
57723590Sbloom 			logent(&msg[1], "FAILED HANDSHAKE");
57817767Sralph 			US_SST(us_s_hand);
57917767Sralph #ifdef GNXSEQ
58013639Ssam 			ulkseq();
58117767Sralph #endif GNXSEQ
58217767Sralph 			systat(Rmtname, SS_INPROGRESS,
58317767Sralph 				strcmp(&msg[1], "CB") == SAME?
58423590Sbloom 				"AWAITING CALLBACK": "FAILED HANDSHAKE");
58513639Ssam 			goto next;
58613639Ssam 		}
58717767Sralph #ifdef GNXSEQ
58813639Ssam 		cmtseq();
58917767Sralph #endif GNXSEQ
59013639Ssam 	}
59117767Sralph 	DEBUG(1, "Rmtname %s, ", Rmtname);
59213639Ssam 	DEBUG(1, "Role %s,  ", Role ? "MASTER" : "SLAVE");
59313639Ssam 	DEBUG(1, "Ifn - %d, ", Ifn);
59413639Ssam 	DEBUG(1, "Loginuser - %s\n", Loginuser);
59513639Ssam 
59625703Sbloom 	ttyn = ttyname(Ifn);
59725703Sbloom 
59813639Ssam 	alarm(MAXMSGTIME);
59918616Sralph 	if (ret=setjmp(Sjbuf))
60013639Ssam 		goto Failure;
60113639Ssam 	ret = startup(Role);
60213639Ssam 	alarm(0);
60313639Ssam 	if (ret != SUCCESS) {
60417767Sralph 		logent("startup", _FAILED);
60513639Ssam Failure:
60617767Sralph 		US_SST(us_s_start);
60718616Sralph 		systat(Rmtname, SS_FAIL, ret > 0 ? "CONVERSATION FAILED" :
60818616Sralph 			"STARTUP FAILED");
60913639Ssam 		goto next;
61017767Sralph 	} else {
61125703Sbloom 		if (ttyn != NULL) {
61225703Sbloom 			char startupmsg[BUFSIZ];
61325703Sbloom 			extern int linebaudrate;
61425703Sbloom 			sprintf(startupmsg, "startup %s %d baud", &ttyn[5],
61525703Sbloom 				linebaudrate);
61625703Sbloom 			logent(startupmsg, "OK");
61725703Sbloom 		} else
61825703Sbloom 			logent("startup", "OK");
61917767Sralph 		US_SST(us_s_gress);
62013639Ssam 		systat(Rmtname, SS_INPROGRESS, "TALKING");
62113639Ssam 		ret = cntrl(Role, wkpre);
62213639Ssam 		DEBUG(1, "cntrl - %d\n", ret);
62313639Ssam 		signal(SIGINT, SIG_IGN);
62413639Ssam 		signal(SIGHUP, SIG_IGN);
62513639Ssam 		signal(SIGALRM, timeout);
62617767Sralph 		if (ret == SUCCESS) {
62713639Ssam 			logent("conversation complete", "OK");
62817767Sralph 			US_SST(us_s_ok);
62913639Ssam 			rmstat(Rmtname);
63013639Ssam 
63117767Sralph 		} else {
63217767Sralph 			logent("conversation complete", _FAILED);
63317767Sralph 			US_SST(us_s_cf);
63417767Sralph 			systat(Rmtname, SS_FAIL, "CONVERSATION FAILED");
63513639Ssam 		}
63613639Ssam 		alarm(MAXMSGTIME);
63713639Ssam 		DEBUG(4, "send OO %d,", ret);
63813639Ssam 		if (!setjmp(Sjbuf)) {
63913639Ssam 			for (;;) {
64013639Ssam 				omsg('O', "OOOOO", Ofn);
64113639Ssam 				ret = imsg(msg, Ifn);
64213639Ssam 				if (ret != 0)
64313639Ssam 					break;
64413639Ssam 				if (msg[0] == 'O')
64513639Ssam 					break;
64613639Ssam 			}
64713639Ssam 		}
64813639Ssam 		alarm(0);
64917767Sralph 		clsacu();
65017767Sralph 		rmlock(CNULL);
65113639Ssam 	}
65213639Ssam next:
65313639Ssam 	if (!onesys) {
65413639Ssam 		goto loop;
65513639Ssam 	}
65613639Ssam 	cleanup(0);
65713639Ssam }
65813639Ssam 
65917767Sralph #ifndef	USG
66013639Ssam struct sgttyb Hupvec;
66113639Ssam #endif
66213639Ssam 
66325703Sbloom /*
66425703Sbloom  *	cleanup and exit with "code" status
66513639Ssam  */
66613639Ssam cleanup(code)
66713639Ssam register int code;
66813639Ssam {
66913639Ssam 	signal(SIGINT, SIG_IGN);
67013639Ssam 	signal(SIGHUP, SIG_IGN);
67113639Ssam 	rmlock(CNULL);
67225703Sbloom 	sleep(5);			/* Wait for any pending output	  */
67313639Ssam 	clsacu();
67413639Ssam 	logcls();
67513639Ssam 	if (Role == SLAVE) {
67617767Sralph 		if (!IsTcpIp) {
67717767Sralph #ifdef USG
67813639Ssam 			Savettyb.c_cflag |= HUPCL;
67923590Sbloom 			(void) ioctl(0, TCSETA, &Savettyb);
68017767Sralph #else !USG
68123590Sbloom 			(void) ioctl(0, TIOCHPCL, STBNULL);
68218616Sralph #ifdef TIOCSDTR
68323590Sbloom 			(void) ioctl(0, TIOCCDTR, STBNULL);
68418616Sralph 			sleep(2);
68523590Sbloom 			(void) ioctl(0, TIOCSDTR, STBNULL);
68618616Sralph #else !TIOCSDTR
68723590Sbloom 			(void) ioctl(0, TIOCGETP, &Hupvec);
68813639Ssam 			Hupvec.sg_ispeed = B0;
68913639Ssam 			Hupvec.sg_ospeed = B0;
69023590Sbloom 			(void) ioctl(0, TIOCSETP, &Hupvec);
69125703Sbloom #endif !TIOCSDTR
69213639Ssam 			sleep(2);
69323590Sbloom 			(void) ioctl(0, TIOCSETP, &Savettyb);
69417767Sralph 			/* make *sure* exclusive access is off */
69523590Sbloom 			(void) ioctl(0, TIOCNXCL, STBNULL);
69617767Sralph #endif !USG
69713639Ssam 		}
69813639Ssam 		if (ttyn != NULL)
69913639Ssam 			chmod(ttyn, 0600);
70013639Ssam 	}
70113639Ssam 	if (Ofn != -1) {
70213639Ssam 		if (Role == MASTER)
70313639Ssam 			write(Ofn, EOTMSG, strlen(EOTMSG));
70413639Ssam 		close(Ifn);
70513639Ssam 		close(Ofn);
70613639Ssam 	}
70718616Sralph #ifdef DIALINOUT
70818616Sralph 	/* reenable logins on dialout */
70918616Sralph 	reenable();
71018616Sralph #endif DIALINOUT
71113639Ssam 	if (code == 0)
71213639Ssam 		xuuxqt();
71317767Sralph 	else
71417767Sralph 		DEBUG(1, "exit code %d\n", code);
71525703Sbloom 	setdebug (DBG_CLEAN);
71613639Ssam 	exit(code);
71713639Ssam }
71813639Ssam 
71925703Sbloom /*
72025703Sbloom  *	on interrupt - remove locks and exit
72113639Ssam  */
72213639Ssam 
72313639Ssam onintr(inter)
72413639Ssam register int inter;
72513639Ssam {
72613639Ssam 	char str[30];
72713639Ssam 	signal(inter, SIG_IGN);
72813639Ssam 	sprintf(str, "SIGNAL %d", inter);
72913639Ssam 	logent(str, "CAUGHT");
73017767Sralph 	US_SST(us_s_intr);
73123590Sbloom 	if (*Rmtname && strncmp(Rmtname, Myname, MAXBASENAME))
73217767Sralph 		systat(Rmtname, SS_FAIL, str);
73317767Sralph 	if (inter == SIGPIPE && !onesys)
73417767Sralph 		longjmp(Pipebuf, 1);
73513639Ssam 	cleanup(inter);
73613639Ssam }
73713639Ssam 
73813639Ssam /*
73913639Ssam  * Catch a special signal
74013639Ssam  * (SIGFPE, ugh), and toggle debugging between 0 and 30.
74113639Ssam  * Handy for looking in on long running uucicos.
74213639Ssam  */
74325703Sbloom dbg_signal()
74413639Ssam {
74525703Sbloom 	Debug = (Debug == 0) ? 30 : 0;
74625703Sbloom 	setdebug(DBG_PERM);
74725703Sbloom 	if (Debug > 0)
74825703Sbloom 		logent("Signal Enabled", "DEBUG");
74925703Sbloom }
75017767Sralph 
75125703Sbloom 
75225703Sbloom /*
75325703Sbloom  * Check debugging requests, and open RMTDEBUG audit file if necessary. If an
75425703Sbloom  * audit file is needed, the parm argument indicates how to create the file:
75525703Sbloom  *
75625703Sbloom  *	DBG_TEMP  - Open a temporary file, with filename = RMTDEBUG/pid.
75725703Sbloom  *	DBG_PERM  - Open a permanent audit file, filename = RMTDEBUG/Rmtname.
75825703Sbloom  *		    If a temp file already exists, it is mv'ed to be permanent.
75925703Sbloom  *	DBG_CLEAN - Cleanup; unlink temp files.
76025703Sbloom  *
76125703Sbloom  * Restrictions - this code can only cope with one open debug file at a time.
76225703Sbloom  * Each call creates a new file; if an old one of the same name exists it will
76325703Sbloom  * be overwritten.
76425703Sbloom  */
76525703Sbloom setdebug(parm)
76625703Sbloom int parm;
76725703Sbloom {
76825703Sbloom 	char buf[BUFSIZ];		/* Buffer for building filenames     */
76925703Sbloom 	static char *temp = NULL;	/* Ptr to temporary file name	     */
77025703Sbloom 	static int auditopen = 0;	/* Set to 1 when we open a file	     */
77125703Sbloom 	struct stat stbuf;		/* File status buffer		     */
77225703Sbloom 
77325703Sbloom 	/*
77425703Sbloom 	 * If movement or cleanup of a temp file is indicated, we do it no
77525703Sbloom 	 * matter what.
77625703Sbloom 	 */
77725703Sbloom 	if (temp != CNULL && parm == DBG_PERM) {
77825703Sbloom 		sprintf(buf, "%s/%s", RMTDEBUG, Rmtname);
77925703Sbloom 		unlink(buf);
78025703Sbloom 		if (link(temp, buf) != 0) {
78123590Sbloom 			Debug = 0;
78225703Sbloom 			assert("RMTDEBUG LINK FAIL", temp, errno);
78325703Sbloom 			cleanup(1);
78425703Sbloom 		}
78525703Sbloom 		parm = DBG_CLEAN;
78623590Sbloom 	}
78725703Sbloom 	if (parm == DBG_CLEAN) {
78825703Sbloom 		if (temp != CNULL) {
78925703Sbloom 			unlink(temp);
79025703Sbloom 			free(temp);
79125703Sbloom 			temp = CNULL;
79225703Sbloom 		}
79325703Sbloom 		return;
79425703Sbloom 	}
79525703Sbloom 
79625703Sbloom 	if (Debug == 0)
79725703Sbloom 		return;		/* Gotta be in debug to come here.   */
79825703Sbloom 
79925703Sbloom 	/*
80025703Sbloom 	 * If we haven't opened a file already, we can just return if it's
80125703Sbloom 	 * alright to use the stderr we came in with. We can if:
80225703Sbloom 	 *
80325703Sbloom 	 *	Role == MASTER, and Stderr is a regular file, a TTY or a pipe.
80425703Sbloom 	 *
80525703Sbloom 	 * Caution: Detecting when stderr is a pipe is tricky, because the 4.2
80625703Sbloom 	 * man page for fstat(2) disagrees with reality, and System V leaves it
80725703Sbloom 	 * undefined, which means different implementations act differently.
80825703Sbloom 	 */
80925703Sbloom 	if (!auditopen && Role == MASTER) {
81025703Sbloom 		if (isatty(fileno(stderr)))
81125703Sbloom 			return;
81225703Sbloom 		else if (fstat(fileno(stderr), &stbuf) == 0) {
81325703Sbloom #ifdef USG
81425703Sbloom 			/* Is Regular File or Fifo   */
81525703Sbloom 			if ((stbuf.st_mode & 0060000) == 0)
81625703Sbloom 				return;
81725703Sbloom #else !USG
81817767Sralph #ifdef BSD4_2
81925703Sbloom 					/* Is Regular File */
82025703Sbloom 			if ((stbuf.st_mode & S_IFMT) == S_IFREG ||
82125703Sbloom 			    stbuf.st_mode == 0)		/* Is a pipe */
82225703Sbloom 				return;
82325703Sbloom #else !BSD4_2
82425703Sbloom 					 /* Is Regular File or Pipe  */
82525703Sbloom 			if ((stbuf.st_mode & S_IFMT) == S_IFREG)
82625703Sbloom 				return;
82725703Sbloom #endif BSD4_2
82825703Sbloom #endif USG
82925703Sbloom 		}
83017767Sralph 	}
83113639Ssam 
83225703Sbloom 	/*
83325703Sbloom 	 * We need RMTDEBUG directory to do auditing. If the file doesn't exist,
83425703Sbloom 	 * then we forget about debugging; if it exists but has improper owner-
83525703Sbloom 	 * ship or modes, we gripe about it in ERRLOG.
83625703Sbloom 	 */
83725703Sbloom 	if (stat(RMTDEBUG, &stbuf) != SUCCESS) {
83825703Sbloom 		Debug = 0;
83925703Sbloom 		return;
84025703Sbloom 	}
84125703Sbloom 	if ((geteuid() != stbuf.st_uid) ||	  	/* We must own it    */
84225703Sbloom 	    ((stbuf.st_mode & 0170700) != 040700)) {	/* Directory, rwx    */
84325703Sbloom 		Debug = 0;
84425703Sbloom 		assert("INVALID RMTDEBUG DIRECTORY:", RMTDEBUG, stbuf.st_mode);
84525703Sbloom 		return;
84625703Sbloom 	}
84713639Ssam 
84825703Sbloom 	if (parm == DBG_TEMP) {
84925703Sbloom 		sprintf(buf, "%s/%d", RMTDEBUG, getpid());
85025703Sbloom 		temp = malloc(strlen (buf) + 1);
85125703Sbloom 		if (temp == CNULL) {
85225703Sbloom 			Debug = 0;
85325703Sbloom 			assert("RMTDEBUG MALLOC ERROR:", temp, errno);
85425703Sbloom 			cleanup(1);
85525703Sbloom 		}
85625703Sbloom 		strcpy(temp, buf);
85725703Sbloom 	} else
85825703Sbloom 		sprintf(buf, "%s/%s", RMTDEBUG, Rmtname);
85913639Ssam 
86025703Sbloom 	unlink(buf);
86125703Sbloom 	if (freopen(buf, "w", stderr) != stderr) {
86225703Sbloom 		Debug = 0;
86325703Sbloom 		assert("FAILED RMTDEBUG FILE OPEN:", buf, errno);
86425703Sbloom 		cleanup(1);
86525703Sbloom 	}
86625703Sbloom 	setbuf(stderr, CNULL);
86725703Sbloom 	auditopen = 1;
86813639Ssam }
86913639Ssam 
87023590Sbloom /*
87125703Sbloom  *	catch SIGALRM routine
87213639Ssam  */
87313639Ssam timeout()
87413639Ssam {
87523590Sbloom 	extern int HaveSentHup;
87623590Sbloom 	if (!HaveSentHup) {
87723590Sbloom 		logent(Rmtname, "TIMEOUT");
87823590Sbloom 		if (*Rmtname && strncmp(Rmtname, Myname, MAXBASENAME)) {
87923590Sbloom 			US_SST(us_s_tmot);
88023590Sbloom 			systat(Rmtname, SS_FAIL, "TIMEOUT");
88123590Sbloom 		}
88217767Sralph 	}
88313639Ssam 	longjmp(Sjbuf, 1);
88413639Ssam }
88513639Ssam 
88613639Ssam static char *
88713639Ssam pskip(p)
88813639Ssam register char *p;
88913639Ssam {
89017767Sralph 	while(*p && *p != ' ')
89113639Ssam 		++p;
89223590Sbloom 	while(*p && *p == ' ')
89317767Sralph 		*p++ = 0;
89417767Sralph 	return p;
89513639Ssam }
896