xref: /csrg-svn/usr.bin/uucp/uucico/cico.c (revision 25963)
113639Ssam #ifndef lint
2*25963Sbloom static char sccsid[] = "@(#)cico.c	5.12 (Berkeley) 01/24/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 
10213639Ssam 	signal(SIGINT, onintr);
10313639Ssam 	signal(SIGHUP, onintr);
10413639Ssam 	signal(SIGQUIT, onintr);
10513639Ssam 	signal(SIGTERM, onintr);
10613639Ssam 	signal(SIGPIPE, onintr);	/* 4.1a tcp-ip stupidity */
10725703Sbloom 	signal(SIGFPE, dbg_signal);
10813639Ssam 	ret = guinfo(getuid(), User, msg);
10913639Ssam 	strcpy(Loginuser, User);
11023590Sbloom 	uucpname(Myname);
11117767Sralph 	ASSERT(ret == 0, "BAD UID", CNULL, ret);
11213639Ssam 
11325703Sbloom 	setbuf (stderr, CNULL);
11425703Sbloom 
11525703Sbloom 	rflags[0] = '\0';
11613639Ssam 	umask(WFMASK);
11713639Ssam 	strcpy(Rmtname, Myname);
11813639Ssam 	Ifn = Ofn = -1;
11913639Ssam 	while(argc>1 && argv[1][0] == '-'){
12013639Ssam 		switch(argv[1][1]){
12113639Ssam 		case 'd':
12213639Ssam 			Spool = &argv[1][2];
12313639Ssam 			break;
12413639Ssam 		case 'g':
12518616Sralph 		case 'p':
12618616Sralph 			MaxGrade = DefMaxGrade = argv[1][2];
12713639Ssam 			break;
12813639Ssam 		case 'r':
12913639Ssam 			Role = atoi(&argv[1][2]);
13013639Ssam 			break;
13117767Sralph 		case 'R':
13217767Sralph 			ReverseRole++;
13317767Sralph 			Role = MASTER;
13417767Sralph 			break;
13513639Ssam 		case 's':
13623590Sbloom 			strncpy(Rmtname, &argv[1][2], MAXBASENAME);
13723590Sbloom 			Rmtname[MAXBASENAME] = '\0';
13813639Ssam 			if (Rmtname[0] != '\0')
13913639Ssam 				onesys = 1;
14013639Ssam 			break;
14113639Ssam 		case 'x':
14213639Ssam 			Debug = atoi(&argv[1][2]);
14313639Ssam 			if (Debug <= 0)
14413639Ssam 				Debug = 1;
14525703Sbloom 			strcat(rflags, argv[1]);
14613639Ssam 			break;
14718616Sralph 		case 't':
14818616Sralph 			turntime = atoi(&argv[1][2])*60;/* minutes to seconds */
14918616Sralph 			break;
15017767Sralph 		case 'L':	/* local calls only */
15117767Sralph 			LocalOnly++;
15217767Sralph 			break;
15323590Sbloom #ifdef NOGETPEER
15417767Sralph 		case 'h':
15517767Sralph 			Hostnumber = inet_addr(&argv[1][2]);
15617767Sralph 			break;
15723590Sbloom #endif NOGETPEER
15813639Ssam 		default:
15917767Sralph 			printf("unknown flag %s (ignored)\n", argv[1]);
16013639Ssam 			break;
16113639Ssam 		}
16213639Ssam 		--argc;  argv++;
16313639Ssam 	}
16413639Ssam 
16517767Sralph 	while (argc > 1) {
16625703Sbloom 		fprintf(stderr, "unknown argument %s (ignored)\n", argv[1]);
16717767Sralph 		--argc; argv++;
16817767Sralph 	}
16917767Sralph 
17025124Sbloom 	/* Try to run as uucp */
17117767Sralph 	setgid(getegid());
17217767Sralph 	setuid(geteuid());
17317767Sralph #ifdef	TIOCNOTTY
17417767Sralph 	/*
17517767Sralph 	 * detach uucico from controlling terminal
17617767Sralph 	 * to defend against rlogind sending us a SIGKILL (!!!)
17717767Sralph 	 */
17817767Sralph 	if (Role == MASTER && (ret = open("/dev/tty", 2)) >= 0) {
17917767Sralph 		ioctl(ret, TIOCNOTTY, STBNULL);
18017767Sralph 		close(ret);
18117767Sralph 	}
18217767Sralph #endif TIOCNOTTY
18317767Sralph #ifdef BSD4_2
18425517Stef 	if (getpgrp(0) == 0) { /* We have no controlling terminal */
18517767Sralph 		setpgrp(0, getpid());
18617767Sralph 	}
18717767Sralph #endif BSD4_2
18817767Sralph 
18917767Sralph 	ret = subchdir(Spool);
19017767Sralph 	ASSERT(ret >= 0, "CHDIR FAILED", Spool, ret);
19113639Ssam 	strcpy(Wrkdir, Spool);
19213639Ssam 
19325703Sbloom 	if (Debug) {
19425703Sbloom 		if (Role == MASTER)
19525703Sbloom 			chkdebug();
19625703Sbloom 		setdebug ((Role == SLAVE) ? DBG_TEMP : DBG_PERM);
19725703Sbloom 		if (Debug > 0)
19825703Sbloom 			logent ("Local Enabled", "DEBUG");
19925703Sbloom 	}
20025703Sbloom 
20125703Sbloom 	/*
20225703Sbloom 	 * First time through: If we're the slave, do initial checking.
20325703Sbloom 	 */
20413639Ssam 	if (Role == SLAVE) {
20517767Sralph 		/* check for /etc/nologin */
20625124Sbloom 		if (access(NOLOGIN, 0) == 0) {
20717767Sralph 			logent(NOLOGIN, "UUCICO SHUTDOWN");
20823590Sbloom 			if (Debug > 4)
20917767Sralph 				logent("DEBUGGING", "continuing anyway");
21017767Sralph 			else
21117767Sralph 				cleanup(1);
21217767Sralph 		}
21325703Sbloom 		Ifn = 0;
21425703Sbloom 		Ofn = 1;
21517767Sralph #ifdef	TCPIP
21617767Sralph 		/*
21717767Sralph 		 * Determine if we are on TCPIP
21817767Sralph 		 */
21925703Sbloom 		if (isatty(Ifn) < 0) {
22017767Sralph 			IsTcpIp = 1;
22117767Sralph 			DEBUG(4, "TCPIP connection -- ioctl-s disabled\n", CNULL);
22223590Sbloom 		} else
22323590Sbloom 			IsTcpIp = 0;
22417767Sralph #endif TCPIP
22513639Ssam 		/* initial handshake */
22613639Ssam 		onesys = 1;
22717767Sralph 		if (!IsTcpIp) {
22817767Sralph #ifdef	USG
22925703Sbloom 			ret = ioctl(Ifn, TCGETA, &Savettyb);
23013639Ssam 			Savettyb.c_cflag = (Savettyb.c_cflag & ~CS8) | CS7;
23113639Ssam 			Savettyb.c_oflag |= OPOST;
23213639Ssam 			Savettyb.c_lflag |= (ISIG|ICANON|ECHO);
23317767Sralph #else !USG
23425703Sbloom 			ret = ioctl(Ifn, TIOCGETP, &Savettyb);
23513639Ssam 			Savettyb.sg_flags |= ECHO;
23613639Ssam 			Savettyb.sg_flags &= ~RAW;
23717767Sralph #endif !USG
23825703Sbloom 			ttyn = ttyname(Ifn);
23913639Ssam 		}
24013639Ssam 		fixmode(Ifn);
24125703Sbloom 
24225703Sbloom 		/*
24325703Sbloom 		 * Initial Message -- tell them we're here, and who we are.
24425703Sbloom 		 */
24518616Sralph 		sprintf(msg, "here=%s", Myfullname);
24617767Sralph 		omsg('S', msg, Ofn);
24713639Ssam 		signal(SIGALRM, timeout);
24813639Ssam 		alarm(MAXMSGTIME);
24913639Ssam 		if (setjmp(Sjbuf)) {
25013639Ssam 			/* timed out */
25117767Sralph 			if (!IsTcpIp) {
25217767Sralph #ifdef	USG
25325703Sbloom 				ret = ioctl(Ifn, TCSETA, &Savettyb);
25425703Sbloom 
25523590Sbloom #else	!USG
25625703Sbloom 				ret = ioctl(Ifn, TIOCSETP, &Savettyb);
25723590Sbloom #endif !USG
25813639Ssam 			}
25917767Sralph 			cleanup(0);
26013639Ssam 		}
26113639Ssam 		for (;;) {
26213639Ssam 			ret = imsg(msg, Ifn);
26325703Sbloom 			if (ret != SUCCESS) {
26413639Ssam 				alarm(0);
26517767Sralph 				if (!IsTcpIp) {
26617767Sralph #ifdef	USG
26725703Sbloom 					ret = ioctl(Ifn, TCSETA, &Savettyb);
26823590Sbloom #else	!USG
26925703Sbloom 					ret = ioctl(Ifn, TIOCSETP, &Savettyb);
27023590Sbloom #endif !USG
27113639Ssam 				}
27217767Sralph 				cleanup(0);
27313639Ssam 			}
27413639Ssam 			if (msg[0] == 'S')
27513639Ssam 				break;
27613639Ssam 		}
27713639Ssam 		alarm(0);
27813639Ssam 		q = &msg[1];
27913639Ssam 		p = pskip(q);
28023590Sbloom 		strncpy(Rmtname, q, MAXBASENAME);
28123590Sbloom 		Rmtname[MAXBASENAME] = '\0';
28225703Sbloom 
28325703Sbloom 		/*
28425703Sbloom 		 * Now that we know who they are, give the audit file the right
28525703Sbloom 		 * name.
28625703Sbloom 		 */
28725703Sbloom 		setdebug (DBG_PERM);
28813639Ssam 		DEBUG(4, "sys-%s\n", Rmtname);
28923725Sbloom 		/* The versys will also do an alias on the incoming name */
29023725Sbloom 		if (versys(&Rmtname)) {
29123725Sbloom 			/* If we don't know them, we won't talk to them... */
29223590Sbloom #ifdef	NOSTRANGERS
29323590Sbloom 			logent(Rmtname, "UNKNOWN HOST");
29423590Sbloom 			omsg('R', "You are unknown to me", Ofn);
29523590Sbloom 			cleanup(0);
29623725Sbloom #endif	NOSTRANGERS
29723590Sbloom 		}
29817767Sralph #ifdef BSDTCP
29917767Sralph 		/* we must make sure they are really who they say they
30017767Sralph 		 * are. We compare the hostnumber with the number in the hosts
30117767Sralph 		 * table for the site they claim to be.
30217767Sralph 		 */
30317767Sralph 		if (IsTcpIp) {
30417767Sralph 			struct hostent *hp;
30517767Sralph 			char *cpnt, *inet_ntoa();
30625703Sbloom 			int fromlen;
30717767Sralph 			struct sockaddr_in from;
30825124Sbloom 			extern char PhoneNumber[];
30917767Sralph 
31023590Sbloom #ifdef	NOGETPEER
31123590Sbloom 			from.sin_addr.s_addr = Hostnumber;
31223590Sbloom 			from.sin_family = AF_INET;
31323590Sbloom #else	!NOGETPEER
31425703Sbloom 			fromlen = sizeof(from);
31525703Sbloom 			if (getpeername(Ifn, &from, &fromlen) < 0) {
31617767Sralph 				logent(Rmtname, "NOT A TCP CONNECTION");
31717767Sralph 				omsg('R', "NOT TCP", Ofn);
31817767Sralph 				cleanup(0);
31917767Sralph 			}
32023590Sbloom #endif	!NOGETPEER
32117767Sralph 			hp = gethostbyaddr(&from.sin_addr,
32217767Sralph 				sizeof (struct in_addr), from.sin_family);
32325703Sbloom 			if (hp == NULL) {
32417767Sralph 				/* security break or just old host table? */
32517767Sralph 				logent(Rmtname, "UNKNOWN IP-HOST Name =");
32617767Sralph 				cpnt = inet_ntoa(from.sin_addr),
32717767Sralph 				logent(cpnt, "UNKNOWN IP-HOST Number =");
32817767Sralph 				sprintf(wkpre, "%s/%s isn't in my host table",
32917767Sralph 					Rmtname, cpnt);
33017767Sralph 				omsg('R' ,wkpre ,Ofn);
33117767Sralph 				cleanup(0);
33217767Sralph 			}
33325703Sbloom 			if (Debug > 99)
33417767Sralph 				logent(Rmtname,"Request from IP-Host name =");
33525124Sbloom 			/*
33625124Sbloom 			 * The following is to determine if the name given us by
33725124Sbloom 			 * the Remote uucico matches any of the names
33817767Sralph 			 * given its network number (remote machine) in our
33917767Sralph 			 * host table.
34025124Sbloom 			 * We could check the aliases, but that won't work in
34125124Sbloom 			 * all cases (like if you are running the domain
34225124Sbloom 			 * server, where you don't get any aliases). The only
34325124Sbloom 			 * reliable way I can think of that works in ALL cases
34425124Sbloom 			 * is too look up the site in L.sys and see if the
34525124Sbloom 			 * sitename matches what we would call him if we
34625124Sbloom 			 * originated the call.
34717767Sralph 			 */
34825124Sbloom 			/* PhoneNumber contains the official network name of the 			   host we are checking. (set in versys.c) */
34925124Sbloom 			if (sncncmp(PhoneNumber, hp->h_name, SYSNSIZE) == 0) {
35017767Sralph 				if (Debug > 99)
35117767Sralph 					logent(q,"Found in host Tables");
35225124Sbloom 			} else {
35325124Sbloom 				logent(hp->h_name, "FORGED HOSTNAME");
35425124Sbloom 				logent(inet_ntoa(from.sin_addr), "ORIGINATED AT");
35525124Sbloom 				logent(PhoneNumber, "SHOULD BE");
35625124Sbloom 				sprintf(wkpre, "You're not who you claim to be: %s !=  %s", hp->h_name, PhoneNumber);
35725124Sbloom 				omsg('R', wkpre, Ofn);
35825124Sbloom 				cleanup(0);
35917767Sralph 			}
36017767Sralph 		}
36117767Sralph #endif	BSDTCP
36217767Sralph 
36325703Sbloom 		if (mlock(Rmtname)) {
36413639Ssam 			omsg('R', "LCK", Ofn);
36513639Ssam 			cleanup(0);
36613639Ssam 		}
36713639Ssam 		else if (callback(Loginuser)) {
36813639Ssam 			signal(SIGINT, SIG_IGN);
36913639Ssam 			signal(SIGHUP, SIG_IGN);
37013639Ssam 			omsg('R', "CB", Ofn);
37113639Ssam 			logent("CALLBACK", "REQUIRED");
37213639Ssam 			/*  set up for call back  */
37317767Sralph 			systat(Rmtname, SS_CALLBACK, "CALLING BACK");
37413639Ssam 			gename(CMDPRE, Rmtname, 'C', file);
37513639Ssam 			close(creat(subfile(file), 0666));
37613639Ssam 			xuucico(Rmtname);
37713639Ssam 			cleanup(0);
37813639Ssam 		}
37913639Ssam 		seq = 0;
38013639Ssam 		while (*p == '-') {
38113639Ssam 			q = pskip(p);
38213639Ssam 			switch(*(++p)) {
38313639Ssam 			case 'x':
38425703Sbloom 				if (Debug == 0) {
38525703Sbloom 					Debug = atoi(++p);
38625703Sbloom 					if (Debug <= 0)
38725703Sbloom 						Debug = 1;
38825703Sbloom 					setdebug(DBG_PERM);
38925703Sbloom 					if (Debug > 0)
39025703Sbloom 						logent("Remote Enabled", "DEBUG");
39125703Sbloom 				} else {
39225703Sbloom 					DEBUG(1, "Remote debug request ignored\n",
39325703Sbloom 					   CNULL);
39425703Sbloom 				}
39513639Ssam 				break;
39613639Ssam 			case 'Q':
39713639Ssam 				seq = atoi(++p);
39813639Ssam 				break;
39918616Sralph 			case 'p':
40018616Sralph 				MaxGrade = DefMaxGrade = *++p;
40118616Sralph 				DEBUG(4, "MaxGrade set to %c\n", MaxGrade);
40218616Sralph 				break;
40323590Sbloom 			case 'v':
40423590Sbloom 				if (strncmp(p, "grade", 5) == 0) {
40523590Sbloom 					p += 6;
40623590Sbloom 					MaxGrade = DefMaxGrade = *p++;
40723590Sbloom 					DEBUG(4, "MaxGrade set to %c\n", MaxGrade);
40823590Sbloom 				}
40923590Sbloom 				break;
41013639Ssam 			default:
41113639Ssam 				break;
41213639Ssam 			}
41313639Ssam 			p = q;
41413639Ssam 		}
41513639Ssam 		if (callok(Rmtname) == SS_BADSEQ) {
41613639Ssam 			logent("BADSEQ", "PREVIOUS");
41713639Ssam 			omsg('R', "BADSEQ", Ofn);
41813639Ssam 			cleanup(0);
41913639Ssam 		}
42017767Sralph #ifdef GNXSEQ
42113639Ssam 		if ((ret = gnxseq(Rmtname)) == seq) {
42213639Ssam 			omsg('R', "OK", Ofn);
42313639Ssam 			cmtseq();
42417767Sralph 		} else {
42517767Sralph #else !GNXSEQ
42617767Sralph 		if (seq == 0)
42717767Sralph 			omsg('R', "OK", Ofn);
42813639Ssam 		else {
42917767Sralph #endif !GNXSEQ
43013639Ssam 			systat(Rmtname, Stattype[7], Stattext[7]);
43123590Sbloom 			logent("BAD SEQ", "FAILED HANDSHAKE");
43217767Sralph #ifdef GNXSEQ
43313639Ssam 			ulkseq();
43417767Sralph #endif GNXSEQ
43513639Ssam 			omsg('R', "BADSEQ", Ofn);
43613639Ssam 			cleanup(0);
43713639Ssam 		}
43813639Ssam 		if (ttyn != NULL)
43913639Ssam 			chmod(ttyn, 0600);
44013639Ssam 	}
44117767Sralph 
44213639Ssam loop:
44317767Sralph 	if(setjmp(Pipebuf)) {	/* come here on SIGPIPE	*/
44417767Sralph 		clsacu();
44517767Sralph 		close(Ofn);
44617767Sralph 		close(Ifn);
44717767Sralph 		Ifn = Ofn = -1;
44817767Sralph 		rmlock(CNULL);
44917767Sralph 		sleep(3);
45017767Sralph 	}
45113639Ssam 	if (!onesys) {
45213639Ssam 		ret = gnsys(Rmtname, Spool, CMDPRE);
45325703Sbloom 		setdebug(DBG_PERM);
45413639Ssam 		if (ret == FAIL)
45513639Ssam 			cleanup(100);
45623590Sbloom 		if (ret == SUCCESS)
45713639Ssam 			cleanup(0);
45817767Sralph 	} else if (Role == MASTER && callok(Rmtname) != 0) {
45913639Ssam 		logent("SYSTEM STATUS", "CAN NOT CALL");
46013639Ssam 		cleanup(0);
46113639Ssam 	}
46213639Ssam 
46323590Sbloom 	sprintf(wkpre, "%c.%.*s", CMDPRE, SYSNSIZE, Rmtname);
46413639Ssam 
46517767Sralph 	signal(SIGINT, SIG_IGN);
46617767Sralph 	signal(SIGQUIT, SIG_IGN);
46713639Ssam 	if (Role == MASTER) {
46817767Sralph 		/* check for /etc/nologin */
46925124Sbloom 		if (access(NOLOGIN, 0) == 0) {
47017767Sralph 			logent(NOLOGIN, "UUCICO SHUTDOWN");
47123590Sbloom 			if (Debug > 4)
47217767Sralph 				logent("DEBUGGING", "continuing anyway");
47317767Sralph 			else
47417767Sralph 				cleanup(1);
47517767Sralph 		}
47613639Ssam 		/*  master part */
47713639Ssam 		signal(SIGHUP, SIG_IGN);
47813639Ssam 		if (Ifn != -1 && Role == MASTER) {
47913639Ssam 			write(Ofn, EOTMSG, strlen(EOTMSG));
48013639Ssam 			clsacu();
48113639Ssam 			close(Ofn);
48213639Ssam 			close(Ifn);
48313639Ssam 			Ifn = Ofn = -1;
48413639Ssam 			rmlock(CNULL);
48513639Ssam 			sleep(3);
48613639Ssam 		}
48713639Ssam 		sprintf(msg, "call to %s ", Rmtname);
48825124Sbloom 		if (mlock(Rmtname) != SUCCESS) {
48913639Ssam 			logent(msg, "LOCKED");
49017767Sralph 			US_SST(us_s_lock);
49113639Ssam 			goto next;
49213639Ssam 		}
49313639Ssam 		Ofn = Ifn = conn(Rmtname);
49413639Ssam 		if (Ofn < 0) {
49517767Sralph 			if (Ofn != CF_TIME)
49617767Sralph 				logent(msg, _FAILED);
49717767Sralph 			/* avoid excessive 'wrong time' info */
49823590Sbloom 			if (Stattype[-Ofn] != SS_WRONGTIME){
49917767Sralph 				systat(Rmtname, Stattype[-Ofn], Stattext[-Ofn]);
50017767Sralph 				US_SST(-Ofn);
50117767Sralph 				UB_SST(-Ofn);
50217767Sralph 			}
50313639Ssam 			goto next;
50417767Sralph 		} else {
50513639Ssam 			logent(msg, "SUCCEEDED");
50617767Sralph 			US_SST(us_s_cok);
50717767Sralph 			UB_SST(ub_ok);
50813639Ssam 		}
50917767Sralph #ifdef	TCPIP
51017767Sralph 		/*
51117767Sralph 		 * Determine if we are on TCPIP
51217767Sralph 		 */
51325703Sbloom 		if (isatty(Ifn) == 0) {
51417767Sralph 			IsTcpIp = 1;
51517767Sralph 			DEBUG(4, "TCPIP connection -- ioctl-s disabled\n", CNULL);
51623590Sbloom 		} else
51723590Sbloom 			IsTcpIp = 0;
51817767Sralph #endif
51917767Sralph 
52013639Ssam 		if (setjmp(Sjbuf))
52113639Ssam 			goto next;
52213639Ssam 		signal(SIGALRM, timeout);
52313639Ssam 		alarm(2 * MAXMSGTIME);
52413639Ssam 		for (;;) {
52513639Ssam 			ret = imsg(msg, Ifn);
52613639Ssam 			if (ret != 0) {
52713639Ssam 				alarm(0);
52817767Sralph 				logent("imsg 1", _FAILED);
52917767Sralph 				goto Failure;
53013639Ssam 			}
53113639Ssam 			if (msg[0] == 'S')
53213639Ssam 				break;
53313639Ssam 		}
53413639Ssam 		alarm(MAXMSGTIME);
53517767Sralph #ifdef GNXSEQ
53613639Ssam 		seq = gnxseq(Rmtname);
53717767Sralph #else !GNXSEQ
53817767Sralph 		seq = 0;
53917767Sralph #endif !GNXSEQ
54018616Sralph 		if (MaxGrade != '\177') {
54123590Sbloom 			DEBUG(2, "Max Grade this transfer is %c\n", MaxGrade);
542*25963Sbloom 			sprintf(msg, "%s -Q%d -p%c -vgrade=%c %s",
543*25963Sbloom 				Myname, seq, MaxGrade, MaxGrade, rflags);
544*25963Sbloom 		} else
545*25963Sbloom 			sprintf(msg, "%s -Q%d %s", Myname, seq, rflags);
54613639Ssam 		omsg('S', msg, Ofn);
54713639Ssam 		for (;;) {
54813639Ssam 			ret = imsg(msg, Ifn);
54913639Ssam 			DEBUG(4, "msg-%s\n", msg);
55017767Sralph 			if (ret != SUCCESS) {
55113639Ssam 				alarm(0);
55217767Sralph #ifdef GNXSEQ
55313639Ssam 				ulkseq();
55417767Sralph #endif GNXSEQ
55517767Sralph 				logent("imsg 2", _FAILED);
55617767Sralph 				goto Failure;
55713639Ssam 			}
55813639Ssam 			if (msg[0] == 'R')
55913639Ssam 				break;
56013639Ssam 		}
56113639Ssam 		alarm(0);
56213639Ssam 		if (msg[1] == 'B') {
56313639Ssam 			/* bad sequence */
56423590Sbloom 			logent("BAD SEQ", "FAILED HANDSHAKE");
56517767Sralph 			US_SST(us_s_hand);
56617767Sralph 			systat(Rmtname, SS_BADSEQ, Stattext[SS_BADSEQ]);
56717767Sralph #ifdef GNXSEQ
56813639Ssam 			ulkseq();
56917767Sralph #endif GNXSEQ
57013639Ssam 			goto next;
57113639Ssam 		}
57213639Ssam 		if (strcmp(&msg[1], "OK") != SAME)  {
57323590Sbloom 			logent(&msg[1], "FAILED HANDSHAKE");
57417767Sralph 			US_SST(us_s_hand);
57517767Sralph #ifdef GNXSEQ
57613639Ssam 			ulkseq();
57717767Sralph #endif GNXSEQ
57817767Sralph 			systat(Rmtname, SS_INPROGRESS,
57917767Sralph 				strcmp(&msg[1], "CB") == SAME?
58023590Sbloom 				"AWAITING CALLBACK": "FAILED HANDSHAKE");
58113639Ssam 			goto next;
58213639Ssam 		}
58317767Sralph #ifdef GNXSEQ
58413639Ssam 		cmtseq();
58517767Sralph #endif GNXSEQ
58613639Ssam 	}
58717767Sralph 	DEBUG(1, "Rmtname %s, ", Rmtname);
58813639Ssam 	DEBUG(1, "Role %s,  ", Role ? "MASTER" : "SLAVE");
58913639Ssam 	DEBUG(1, "Ifn - %d, ", Ifn);
59013639Ssam 	DEBUG(1, "Loginuser - %s\n", Loginuser);
59113639Ssam 
59225703Sbloom 	ttyn = ttyname(Ifn);
59325703Sbloom 
59413639Ssam 	alarm(MAXMSGTIME);
59518616Sralph 	if (ret=setjmp(Sjbuf))
59613639Ssam 		goto Failure;
59713639Ssam 	ret = startup(Role);
59813639Ssam 	alarm(0);
59913639Ssam 	if (ret != SUCCESS) {
60017767Sralph 		logent("startup", _FAILED);
60113639Ssam Failure:
60217767Sralph 		US_SST(us_s_start);
60318616Sralph 		systat(Rmtname, SS_FAIL, ret > 0 ? "CONVERSATION FAILED" :
60418616Sralph 			"STARTUP FAILED");
60513639Ssam 		goto next;
60617767Sralph 	} else {
60725703Sbloom 		if (ttyn != NULL) {
60825703Sbloom 			char startupmsg[BUFSIZ];
60925703Sbloom 			extern int linebaudrate;
61025703Sbloom 			sprintf(startupmsg, "startup %s %d baud", &ttyn[5],
61125703Sbloom 				linebaudrate);
61225703Sbloom 			logent(startupmsg, "OK");
61325703Sbloom 		} else
61425703Sbloom 			logent("startup", "OK");
61517767Sralph 		US_SST(us_s_gress);
61613639Ssam 		systat(Rmtname, SS_INPROGRESS, "TALKING");
61713639Ssam 		ret = cntrl(Role, wkpre);
61813639Ssam 		DEBUG(1, "cntrl - %d\n", ret);
61913639Ssam 		signal(SIGINT, SIG_IGN);
62013639Ssam 		signal(SIGHUP, SIG_IGN);
62113639Ssam 		signal(SIGALRM, timeout);
62217767Sralph 		if (ret == SUCCESS) {
62313639Ssam 			logent("conversation complete", "OK");
62417767Sralph 			US_SST(us_s_ok);
62513639Ssam 			rmstat(Rmtname);
62613639Ssam 
62717767Sralph 		} else {
62817767Sralph 			logent("conversation complete", _FAILED);
62917767Sralph 			US_SST(us_s_cf);
63017767Sralph 			systat(Rmtname, SS_FAIL, "CONVERSATION FAILED");
63113639Ssam 		}
63213639Ssam 		alarm(MAXMSGTIME);
63313639Ssam 		DEBUG(4, "send OO %d,", ret);
63413639Ssam 		if (!setjmp(Sjbuf)) {
63513639Ssam 			for (;;) {
63613639Ssam 				omsg('O', "OOOOO", Ofn);
63713639Ssam 				ret = imsg(msg, Ifn);
63813639Ssam 				if (ret != 0)
63913639Ssam 					break;
64013639Ssam 				if (msg[0] == 'O')
64113639Ssam 					break;
64213639Ssam 			}
64313639Ssam 		}
64413639Ssam 		alarm(0);
64517767Sralph 		clsacu();
64617767Sralph 		rmlock(CNULL);
64713639Ssam 	}
64813639Ssam next:
64913639Ssam 	if (!onesys) {
65013639Ssam 		goto loop;
65113639Ssam 	}
65213639Ssam 	cleanup(0);
65313639Ssam }
65413639Ssam 
65517767Sralph #ifndef	USG
65613639Ssam struct sgttyb Hupvec;
65713639Ssam #endif
65813639Ssam 
65925703Sbloom /*
66025703Sbloom  *	cleanup and exit with "code" status
66113639Ssam  */
66213639Ssam cleanup(code)
66313639Ssam register int code;
66413639Ssam {
66513639Ssam 	signal(SIGINT, SIG_IGN);
66613639Ssam 	signal(SIGHUP, SIG_IGN);
66713639Ssam 	rmlock(CNULL);
66825703Sbloom 	sleep(5);			/* Wait for any pending output	  */
66913639Ssam 	clsacu();
67013639Ssam 	logcls();
67113639Ssam 	if (Role == SLAVE) {
67217767Sralph 		if (!IsTcpIp) {
67317767Sralph #ifdef USG
67413639Ssam 			Savettyb.c_cflag |= HUPCL;
67523590Sbloom 			(void) ioctl(0, TCSETA, &Savettyb);
67617767Sralph #else !USG
67723590Sbloom 			(void) ioctl(0, TIOCHPCL, STBNULL);
67818616Sralph #ifdef TIOCSDTR
67923590Sbloom 			(void) ioctl(0, TIOCCDTR, STBNULL);
68018616Sralph 			sleep(2);
68123590Sbloom 			(void) ioctl(0, TIOCSDTR, STBNULL);
68218616Sralph #else !TIOCSDTR
68323590Sbloom 			(void) ioctl(0, TIOCGETP, &Hupvec);
68413639Ssam 			Hupvec.sg_ispeed = B0;
68513639Ssam 			Hupvec.sg_ospeed = B0;
68623590Sbloom 			(void) ioctl(0, TIOCSETP, &Hupvec);
68725703Sbloom #endif !TIOCSDTR
68813639Ssam 			sleep(2);
68923590Sbloom 			(void) ioctl(0, TIOCSETP, &Savettyb);
69017767Sralph 			/* make *sure* exclusive access is off */
69123590Sbloom 			(void) ioctl(0, TIOCNXCL, STBNULL);
69217767Sralph #endif !USG
69313639Ssam 		}
69413639Ssam 		if (ttyn != NULL)
69513639Ssam 			chmod(ttyn, 0600);
69613639Ssam 	}
69713639Ssam 	if (Ofn != -1) {
69813639Ssam 		if (Role == MASTER)
69913639Ssam 			write(Ofn, EOTMSG, strlen(EOTMSG));
70013639Ssam 		close(Ifn);
70113639Ssam 		close(Ofn);
70213639Ssam 	}
70318616Sralph #ifdef DIALINOUT
70418616Sralph 	/* reenable logins on dialout */
70518616Sralph 	reenable();
70618616Sralph #endif DIALINOUT
70713639Ssam 	if (code == 0)
70813639Ssam 		xuuxqt();
70917767Sralph 	else
71017767Sralph 		DEBUG(1, "exit code %d\n", code);
71125703Sbloom 	setdebug (DBG_CLEAN);
71213639Ssam 	exit(code);
71313639Ssam }
71413639Ssam 
71525703Sbloom /*
71625703Sbloom  *	on interrupt - remove locks and exit
71713639Ssam  */
71813639Ssam 
71913639Ssam onintr(inter)
72013639Ssam register int inter;
72113639Ssam {
72213639Ssam 	char str[30];
72313639Ssam 	signal(inter, SIG_IGN);
72413639Ssam 	sprintf(str, "SIGNAL %d", inter);
72513639Ssam 	logent(str, "CAUGHT");
72617767Sralph 	US_SST(us_s_intr);
72723590Sbloom 	if (*Rmtname && strncmp(Rmtname, Myname, MAXBASENAME))
72817767Sralph 		systat(Rmtname, SS_FAIL, str);
72917767Sralph 	if (inter == SIGPIPE && !onesys)
73017767Sralph 		longjmp(Pipebuf, 1);
73113639Ssam 	cleanup(inter);
73213639Ssam }
73313639Ssam 
73413639Ssam /*
73513639Ssam  * Catch a special signal
73613639Ssam  * (SIGFPE, ugh), and toggle debugging between 0 and 30.
73713639Ssam  * Handy for looking in on long running uucicos.
73813639Ssam  */
73925703Sbloom dbg_signal()
74013639Ssam {
74125703Sbloom 	Debug = (Debug == 0) ? 30 : 0;
74225703Sbloom 	setdebug(DBG_PERM);
74325703Sbloom 	if (Debug > 0)
74425703Sbloom 		logent("Signal Enabled", "DEBUG");
74525703Sbloom }
74617767Sralph 
74725703Sbloom 
74825703Sbloom /*
74925703Sbloom  * Check debugging requests, and open RMTDEBUG audit file if necessary. If an
75025703Sbloom  * audit file is needed, the parm argument indicates how to create the file:
75125703Sbloom  *
75225703Sbloom  *	DBG_TEMP  - Open a temporary file, with filename = RMTDEBUG/pid.
75325703Sbloom  *	DBG_PERM  - Open a permanent audit file, filename = RMTDEBUG/Rmtname.
75425703Sbloom  *		    If a temp file already exists, it is mv'ed to be permanent.
75525703Sbloom  *	DBG_CLEAN - Cleanup; unlink temp files.
75625703Sbloom  *
75725703Sbloom  * Restrictions - this code can only cope with one open debug file at a time.
75825703Sbloom  * Each call creates a new file; if an old one of the same name exists it will
75925703Sbloom  * be overwritten.
76025703Sbloom  */
76125703Sbloom setdebug(parm)
76225703Sbloom int parm;
76325703Sbloom {
76425703Sbloom 	char buf[BUFSIZ];		/* Buffer for building filenames     */
76525703Sbloom 	static char *temp = NULL;	/* Ptr to temporary file name	     */
76625703Sbloom 	static int auditopen = 0;	/* Set to 1 when we open a file	     */
76725703Sbloom 	struct stat stbuf;		/* File status buffer		     */
76825703Sbloom 
76925703Sbloom 	/*
77025703Sbloom 	 * If movement or cleanup of a temp file is indicated, we do it no
77125703Sbloom 	 * matter what.
77225703Sbloom 	 */
77325703Sbloom 	if (temp != CNULL && parm == DBG_PERM) {
77425703Sbloom 		sprintf(buf, "%s/%s", RMTDEBUG, Rmtname);
77525703Sbloom 		unlink(buf);
77625703Sbloom 		if (link(temp, buf) != 0) {
77723590Sbloom 			Debug = 0;
77825703Sbloom 			assert("RMTDEBUG LINK FAIL", temp, errno);
77925703Sbloom 			cleanup(1);
78025703Sbloom 		}
78125703Sbloom 		parm = DBG_CLEAN;
78223590Sbloom 	}
78325703Sbloom 	if (parm == DBG_CLEAN) {
78425703Sbloom 		if (temp != CNULL) {
78525703Sbloom 			unlink(temp);
78625703Sbloom 			free(temp);
78725703Sbloom 			temp = CNULL;
78825703Sbloom 		}
78925703Sbloom 		return;
79025703Sbloom 	}
79125703Sbloom 
79225703Sbloom 	if (Debug == 0)
79325703Sbloom 		return;		/* Gotta be in debug to come here.   */
79425703Sbloom 
79525703Sbloom 	/*
79625703Sbloom 	 * If we haven't opened a file already, we can just return if it's
79725703Sbloom 	 * alright to use the stderr we came in with. We can if:
79825703Sbloom 	 *
79925703Sbloom 	 *	Role == MASTER, and Stderr is a regular file, a TTY or a pipe.
80025703Sbloom 	 *
80125703Sbloom 	 * Caution: Detecting when stderr is a pipe is tricky, because the 4.2
80225703Sbloom 	 * man page for fstat(2) disagrees with reality, and System V leaves it
80325703Sbloom 	 * undefined, which means different implementations act differently.
80425703Sbloom 	 */
80525703Sbloom 	if (!auditopen && Role == MASTER) {
80625703Sbloom 		if (isatty(fileno(stderr)))
80725703Sbloom 			return;
80825703Sbloom 		else if (fstat(fileno(stderr), &stbuf) == 0) {
80925703Sbloom #ifdef USG
81025703Sbloom 			/* Is Regular File or Fifo   */
81125703Sbloom 			if ((stbuf.st_mode & 0060000) == 0)
81225703Sbloom 				return;
81325703Sbloom #else !USG
81417767Sralph #ifdef BSD4_2
81525703Sbloom 					/* Is Regular File */
81625703Sbloom 			if ((stbuf.st_mode & S_IFMT) == S_IFREG ||
81725703Sbloom 			    stbuf.st_mode == 0)		/* Is a pipe */
81825703Sbloom 				return;
81925703Sbloom #else !BSD4_2
82025703Sbloom 					 /* Is Regular File or Pipe  */
82125703Sbloom 			if ((stbuf.st_mode & S_IFMT) == S_IFREG)
82225703Sbloom 				return;
82325703Sbloom #endif BSD4_2
82425703Sbloom #endif USG
82525703Sbloom 		}
82617767Sralph 	}
82713639Ssam 
82825703Sbloom 	/*
82925703Sbloom 	 * We need RMTDEBUG directory to do auditing. If the file doesn't exist,
83025703Sbloom 	 * then we forget about debugging; if it exists but has improper owner-
83125703Sbloom 	 * ship or modes, we gripe about it in ERRLOG.
83225703Sbloom 	 */
83325703Sbloom 	if (stat(RMTDEBUG, &stbuf) != SUCCESS) {
83425703Sbloom 		Debug = 0;
83525703Sbloom 		return;
83625703Sbloom 	}
83725703Sbloom 	if ((geteuid() != stbuf.st_uid) ||	  	/* We must own it    */
83825703Sbloom 	    ((stbuf.st_mode & 0170700) != 040700)) {	/* Directory, rwx    */
83925703Sbloom 		Debug = 0;
84025703Sbloom 		assert("INVALID RMTDEBUG DIRECTORY:", RMTDEBUG, stbuf.st_mode);
84125703Sbloom 		return;
84225703Sbloom 	}
84313639Ssam 
84425703Sbloom 	if (parm == DBG_TEMP) {
84525703Sbloom 		sprintf(buf, "%s/%d", RMTDEBUG, getpid());
84625703Sbloom 		temp = malloc(strlen (buf) + 1);
84725703Sbloom 		if (temp == CNULL) {
84825703Sbloom 			Debug = 0;
84925703Sbloom 			assert("RMTDEBUG MALLOC ERROR:", temp, errno);
85025703Sbloom 			cleanup(1);
85125703Sbloom 		}
85225703Sbloom 		strcpy(temp, buf);
85325703Sbloom 	} else
85425703Sbloom 		sprintf(buf, "%s/%s", RMTDEBUG, Rmtname);
85513639Ssam 
85625703Sbloom 	unlink(buf);
85725703Sbloom 	if (freopen(buf, "w", stderr) != stderr) {
85825703Sbloom 		Debug = 0;
85925703Sbloom 		assert("FAILED RMTDEBUG FILE OPEN:", buf, errno);
86025703Sbloom 		cleanup(1);
86125703Sbloom 	}
86225703Sbloom 	setbuf(stderr, CNULL);
86325703Sbloom 	auditopen = 1;
86413639Ssam }
86513639Ssam 
86623590Sbloom /*
86725703Sbloom  *	catch SIGALRM routine
86813639Ssam  */
86913639Ssam timeout()
87013639Ssam {
87123590Sbloom 	extern int HaveSentHup;
87223590Sbloom 	if (!HaveSentHup) {
87323590Sbloom 		logent(Rmtname, "TIMEOUT");
87423590Sbloom 		if (*Rmtname && strncmp(Rmtname, Myname, MAXBASENAME)) {
87523590Sbloom 			US_SST(us_s_tmot);
87623590Sbloom 			systat(Rmtname, SS_FAIL, "TIMEOUT");
87723590Sbloom 		}
87817767Sralph 	}
87913639Ssam 	longjmp(Sjbuf, 1);
88013639Ssam }
88113639Ssam 
88213639Ssam static char *
88313639Ssam pskip(p)
88413639Ssam register char *p;
88513639Ssam {
88617767Sralph 	while(*p && *p != ' ')
88713639Ssam 		++p;
88823590Sbloom 	while(*p && *p == ' ')
88917767Sralph 		*p++ = 0;
89017767Sralph 	return p;
89113639Ssam }
892