xref: /csrg-svn/usr.bin/uucp/uucico/cico.c (revision 25124)
113639Ssam #ifndef lint
2*25124Sbloom static char sccsid[] = "@(#)cico.c	5.9 (Berkeley) 10/09/85";
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",
4113639Ssam 	"DIAL 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 
5813639Ssam 
5917767Sralph int ReverseRole = 0;
6017767Sralph int StdErrIsTty = 0;
6117767Sralph int Role = SLAVE;
6217767Sralph int onesys = 0;
6318616Sralph int turntime = 30 * 60;	/* 30 minutes expressed in seconds */
6417767Sralph extern int LocalOnly;
6518616Sralph extern char MaxGrade, DefMaxGrade;
6618616Sralph extern char Myfullname[];
6717767Sralph 
6817767Sralph #ifdef	USG
6913639Ssam struct termio Savettyb;
7013639Ssam #endif
7117767Sralph #ifndef	USG
7213639Ssam struct sgttyb Savettyb;
7313639Ssam #endif
7413639Ssam 
7513639Ssam /*******
7613639Ssam  *	cico - this program is used  to place a call to a
7713639Ssam  *	remote machine, login, and copy files between the two machines.
7813639Ssam  */
7913639Ssam 
8013639Ssam main(argc, argv)
8113639Ssam register char *argv[];
8213639Ssam {
8313639Ssam 	register int ret;
8413639Ssam 	int seq;
8513639Ssam 	char wkpre[NAMESIZE], file[NAMESIZE];
8617767Sralph 	char msg[MAXFULLNAME], *q, **alias;
8713639Ssam 	register char *p;
8813639Ssam 	extern onintr(), timeout(), setdebug();
8913639Ssam 	extern char *pskip();
9023725Sbloom 	char rflags[MAXFULLNAME];
9113639Ssam 	char *ttyn;
9223590Sbloom #ifdef NOGETPEER
9317767Sralph 	u_long Hostnumber = 0;
9423590Sbloom #endif NOGETPEER
9513639Ssam 
9613639Ssam 	strcpy(Progname, "uucico");
9713639Ssam 
9813639Ssam 	signal(SIGINT, onintr);
9913639Ssam 	signal(SIGHUP, onintr);
10013639Ssam 	signal(SIGQUIT, onintr);
10113639Ssam 	signal(SIGTERM, onintr);
10213639Ssam 	signal(SIGPIPE, onintr);	/* 4.1a tcp-ip stupidity */
10313639Ssam 	signal(SIGFPE, setdebug);
10413639Ssam 	ret = guinfo(getuid(), User, msg);
10513639Ssam 	strcpy(Loginuser, User);
10623590Sbloom 	uucpname(Myname);
10717767Sralph 	ASSERT(ret == 0, "BAD UID", CNULL, ret);
10813639Ssam 
10917767Sralph #ifdef BSD4_2
11017767Sralph 	setlinebuf(stderr);
11117767Sralph #endif
11213639Ssam 	umask(WFMASK);
11313639Ssam 	strcpy(Rmtname, Myname);
11413639Ssam 	Ifn = Ofn = -1;
11513639Ssam 	while(argc>1 && argv[1][0] == '-'){
11613639Ssam 		switch(argv[1][1]){
11713639Ssam 		case 'd':
11813639Ssam 			Spool = &argv[1][2];
11913639Ssam 			break;
12013639Ssam 		case 'g':
12118616Sralph 		case 'p':
12218616Sralph 			MaxGrade = DefMaxGrade = argv[1][2];
12313639Ssam 			break;
12413639Ssam 		case 'r':
12513639Ssam 			Role = atoi(&argv[1][2]);
12613639Ssam 			break;
12717767Sralph 		case 'R':
12817767Sralph 			ReverseRole++;
12917767Sralph 			Role = MASTER;
13017767Sralph 			break;
13113639Ssam 		case 's':
13223590Sbloom 			strncpy(Rmtname, &argv[1][2], MAXBASENAME);
13323590Sbloom 			Rmtname[MAXBASENAME] = '\0';
13413639Ssam 			if (Rmtname[0] != '\0')
13513639Ssam 				onesys = 1;
13613639Ssam 			break;
13713639Ssam 		case 'x':
13817767Sralph 			chkdebug();
13913639Ssam 			Debug = atoi(&argv[1][2]);
14013639Ssam 			if (Debug <= 0)
14113639Ssam 				Debug = 1;
14213639Ssam 			logent("ENABLED", "DEBUG");
14313639Ssam 			break;
14418616Sralph 		case 't':
14518616Sralph 			turntime = atoi(&argv[1][2])*60;/* minutes to seconds */
14618616Sralph 			break;
14717767Sralph 		case 'L':	/* local calls only */
14817767Sralph 			LocalOnly++;
14917767Sralph 			break;
15023590Sbloom #ifdef NOGETPEER
15117767Sralph 		case 'h':
15217767Sralph 			Hostnumber = inet_addr(&argv[1][2]);
15317767Sralph 			break;
15423590Sbloom #endif NOGETPEER
15513639Ssam 		default:
15617767Sralph 			printf("unknown flag %s (ignored)\n", argv[1]);
15713639Ssam 			break;
15813639Ssam 		}
15913639Ssam 		--argc;  argv++;
16013639Ssam 	}
16113639Ssam 
16217767Sralph 	while (argc > 1) {
16317767Sralph 		printf("unknown argument %s (ignored)\n", argv[1]);
16417767Sralph 		--argc; argv++;
16517767Sralph 	}
16617767Sralph 
167*25124Sbloom 	/* Try to run as uucp */
16817767Sralph 	setgid(getegid());
16917767Sralph 	setuid(geteuid());
17017767Sralph #ifdef	TIOCNOTTY
17117767Sralph 	/*
17217767Sralph 	 * detach uucico from controlling terminal
17317767Sralph 	 * to defend against rlogind sending us a SIGKILL (!!!)
17417767Sralph 	 */
17517767Sralph 	if (Role == MASTER && (ret = open("/dev/tty", 2)) >= 0) {
17617767Sralph 		ioctl(ret, TIOCNOTTY, STBNULL);
17717767Sralph 		close(ret);
17817767Sralph 	}
17917767Sralph #endif TIOCNOTTY
18017767Sralph #ifdef BSD4_2
18117767Sralph 	if (getpgrp(0) == 0) { /*We have no controlling terminal */
18217767Sralph 		setpgrp(0, getpid());
18317767Sralph 	}
18417767Sralph #endif BSD4_2
18517767Sralph 
18617767Sralph 	ret = subchdir(Spool);
18717767Sralph 	ASSERT(ret >= 0, "CHDIR FAILED", Spool, ret);
18813639Ssam 	strcpy(Wrkdir, Spool);
18913639Ssam 
19013639Ssam 	if (Role == SLAVE) {
19117767Sralph 		/* check for /etc/nologin */
192*25124Sbloom 		if (access(NOLOGIN, 0) == 0) {
19317767Sralph 			logent(NOLOGIN, "UUCICO SHUTDOWN");
19423590Sbloom 			if (Debug > 4)
19517767Sralph 				logent("DEBUGGING", "continuing anyway");
19617767Sralph 			else
19717767Sralph 				cleanup(1);
19817767Sralph 		}
19917767Sralph #ifdef	TCPIP
20017767Sralph 		/*
20117767Sralph 		 * Determine if we are on TCPIP
20217767Sralph 		 */
20317767Sralph 		if (isatty(0) ==  0) {
20417767Sralph 			IsTcpIp = 1;
20517767Sralph 			DEBUG(4, "TCPIP connection -- ioctl-s disabled\n", CNULL);
20623590Sbloom 		} else
20723590Sbloom 			IsTcpIp = 0;
20817767Sralph #endif TCPIP
20913639Ssam 		/* initial handshake */
21013639Ssam 		onesys = 1;
21117767Sralph 		if (!IsTcpIp) {
21217767Sralph #ifdef	USG
21313639Ssam 			ret = ioctl(0, TCGETA, &Savettyb);
21413639Ssam 			Savettyb.c_cflag = (Savettyb.c_cflag & ~CS8) | CS7;
21513639Ssam 			Savettyb.c_oflag |= OPOST;
21613639Ssam 			Savettyb.c_lflag |= (ISIG|ICANON|ECHO);
21717767Sralph #else !USG
21813639Ssam 			ret = ioctl(0, TIOCGETP, &Savettyb);
21913639Ssam 			Savettyb.sg_flags |= ECHO;
22013639Ssam 			Savettyb.sg_flags &= ~RAW;
22117767Sralph #endif !USG
22213639Ssam 		}
22313639Ssam 		Ifn = 0;
22413639Ssam 		Ofn = 1;
22513639Ssam 		fixmode(Ifn);
22617767Sralph 		sprintf(file,"%s/%d", RMTDEBUG, getpid());
22717767Sralph #ifdef VMS
22817767Sralph 		/* hold the version number down */
22917767Sralph 		unlink(file);
23023590Sbloom #endif VMS
23117767Sralph 		freopen(file, "w", stderr);
23217767Sralph #ifdef BSD4_2
23317767Sralph 		setlinebuf(stderr);
23417767Sralph #else  !BSD4_2
23517767Sralph 		setbuf(stderr, NULL);
23617767Sralph #endif !BSD4_2
23718616Sralph 		sprintf(msg, "here=%s", Myfullname);
23817767Sralph 		omsg('S', msg, Ofn);
23913639Ssam 		signal(SIGALRM, timeout);
24013639Ssam 		alarm(MAXMSGTIME);
24113639Ssam 		if (setjmp(Sjbuf)) {
24213639Ssam 			/* timed out */
24317767Sralph 			if (!IsTcpIp) {
24417767Sralph #ifdef	USG
24513639Ssam 				ret = ioctl(0, TCSETA, &Savettyb);
24623590Sbloom #else	!USG
24713639Ssam 				ret = ioctl(0, TIOCSETP, &Savettyb);
24823590Sbloom #endif !USG
24913639Ssam 			}
25017767Sralph 			cleanup(0);
25113639Ssam 		}
25213639Ssam 		for (;;) {
25313639Ssam 			ret = imsg(msg, Ifn);
25413639Ssam 			if (ret != 0) {
25513639Ssam 				alarm(0);
25617767Sralph 				if (!IsTcpIp) {
25717767Sralph #ifdef	USG
25813639Ssam 					ret = ioctl(0, TCSETA, &Savettyb);
25923590Sbloom #else	!USG
26013639Ssam 					ret = ioctl(0, TIOCSETP, &Savettyb);
26123590Sbloom #endif !USG
26213639Ssam 				}
26317767Sralph 				cleanup(0);
26413639Ssam 			}
26513639Ssam 			if (msg[0] == 'S')
26613639Ssam 				break;
26713639Ssam 		}
26813639Ssam 		alarm(0);
26913639Ssam 		q = &msg[1];
27013639Ssam 		p = pskip(q);
27123590Sbloom 		strncpy(Rmtname, q, MAXBASENAME);
27223590Sbloom 		Rmtname[MAXBASENAME] = '\0';
27317767Sralph 		sprintf(wkpre,"%s/%s", RMTDEBUG, Rmtname);
27417767Sralph 		unlink(wkpre);
27517767Sralph 		if (link(file, wkpre) == 0)
27617767Sralph 			unlink(file);
27713639Ssam 		DEBUG(4, "sys-%s\n", Rmtname);
27823725Sbloom 		/* The versys will also do an alias on the incoming name */
27923725Sbloom 		if (versys(&Rmtname)) {
28023725Sbloom 			/* If we don't know them, we won't talk to them... */
28123590Sbloom #ifdef	NOSTRANGERS
28223590Sbloom 			logent(Rmtname, "UNKNOWN HOST");
28323590Sbloom 			omsg('R', "You are unknown to me", Ofn);
28423590Sbloom 			cleanup(0);
28523725Sbloom #endif	NOSTRANGERS
28623590Sbloom 		}
28717767Sralph #ifdef BSDTCP
28817767Sralph 		/* we must make sure they are really who they say they
28917767Sralph 		 * are. We compare the hostnumber with the number in the hosts
29017767Sralph 		 * table for the site they claim to be.
29117767Sralph 		 */
29217767Sralph 		if (IsTcpIp) {
29317767Sralph 			struct hostent *hp;
29417767Sralph 			char *cpnt, *inet_ntoa();
295*25124Sbloom 			int len;
29617767Sralph 			struct sockaddr_in from;
297*25124Sbloom 			extern char PhoneNumber[];
29817767Sralph 
29923590Sbloom #ifdef	NOGETPEER
30023590Sbloom 			from.sin_addr.s_addr = Hostnumber;
30123590Sbloom 			from.sin_family = AF_INET;
30223590Sbloom #else	!NOGETPEER
303*25124Sbloom 			len = sizeof(from);
304*25124Sbloom 			if (getpeername(0, &from, &len) < 0) {
30517767Sralph 				logent(Rmtname, "NOT A TCP CONNECTION");
30617767Sralph 				omsg('R', "NOT TCP", Ofn);
30717767Sralph 				cleanup(0);
30817767Sralph 			}
30923590Sbloom #endif	!NOGETPEER
31017767Sralph 			hp = gethostbyaddr(&from.sin_addr,
31117767Sralph 				sizeof (struct in_addr), from.sin_family);
31217767Sralph 			if (hp == 0) {
31317767Sralph 				/* security break or just old host table? */
31417767Sralph 				logent(Rmtname, "UNKNOWN IP-HOST Name =");
31517767Sralph 				cpnt = inet_ntoa(from.sin_addr),
31617767Sralph 				logent(cpnt, "UNKNOWN IP-HOST Number =");
31717767Sralph 				sprintf(wkpre, "%s/%s isn't in my host table",
31817767Sralph 					Rmtname, cpnt);
31917767Sralph 				omsg('R' ,wkpre ,Ofn);
32017767Sralph 				cleanup(0);
32117767Sralph 			}
32217767Sralph 			if (Debug>99)
32317767Sralph 				logent(Rmtname,"Request from IP-Host name =");
324*25124Sbloom 			/*
325*25124Sbloom 			 * The following is to determine if the name given us by
326*25124Sbloom 			 * the Remote uucico matches any of the names
32717767Sralph 			 * given its network number (remote machine) in our
32817767Sralph 			 * host table.
329*25124Sbloom 			 * We could check the aliases, but that won't work in
330*25124Sbloom 			 * all cases (like if you are running the domain
331*25124Sbloom 			 * server, where you don't get any aliases). The only
332*25124Sbloom 			 * reliable way I can think of that works in ALL cases
333*25124Sbloom 			 * is too look up the site in L.sys and see if the
334*25124Sbloom 			 * sitename matches what we would call him if we
335*25124Sbloom 			 * originated the call.
33617767Sralph 			 */
337*25124Sbloom 			/* PhoneNumber contains the official network name of the 			   host we are checking. (set in versys.c) */
338*25124Sbloom 			if (sncncmp(PhoneNumber, hp->h_name, SYSNSIZE) == 0) {
33917767Sralph 				if (Debug > 99)
34017767Sralph 					logent(q,"Found in host Tables");
341*25124Sbloom 			} else {
342*25124Sbloom 				logent(hp->h_name, "FORGED HOSTNAME");
343*25124Sbloom 				logent(inet_ntoa(from.sin_addr), "ORIGINATED AT");
344*25124Sbloom 				logent(PhoneNumber, "SHOULD BE");
345*25124Sbloom 				sprintf(wkpre, "You're not who you claim to be: %s !=  %s", hp->h_name, PhoneNumber);
346*25124Sbloom 				omsg('R', wkpre, Ofn);
347*25124Sbloom 				cleanup(0);
34817767Sralph 			}
34917767Sralph 		}
35017767Sralph #endif	BSDTCP
35117767Sralph 
352*25124Sbloom 		if (mlock(Rmtname) == FAIL) {
35313639Ssam 			omsg('R', "LCK", Ofn);
35413639Ssam 			cleanup(0);
35513639Ssam 		}
35613639Ssam 		else if (callback(Loginuser)) {
35713639Ssam 			signal(SIGINT, SIG_IGN);
35813639Ssam 			signal(SIGHUP, SIG_IGN);
35913639Ssam 			omsg('R', "CB", Ofn);
36013639Ssam 			logent("CALLBACK", "REQUIRED");
36113639Ssam 			/*  set up for call back  */
36217767Sralph 			systat(Rmtname, SS_CALLBACK, "CALLING BACK");
36313639Ssam 			gename(CMDPRE, Rmtname, 'C', file);
36413639Ssam 			close(creat(subfile(file), 0666));
36513639Ssam 			xuucico(Rmtname);
36613639Ssam 			cleanup(0);
36713639Ssam 		}
36813639Ssam 		seq = 0;
36913639Ssam 		while (*p == '-') {
37013639Ssam 			q = pskip(p);
37113639Ssam 			switch(*(++p)) {
37213639Ssam 			case 'x':
37313639Ssam 				Debug = atoi(++p);
37413639Ssam 				if (Debug <= 0)
37513639Ssam 					Debug = 1;
37613639Ssam 				break;
37713639Ssam 			case 'Q':
37813639Ssam 				seq = atoi(++p);
37913639Ssam 				break;
38018616Sralph 			case 'p':
38118616Sralph 				MaxGrade = DefMaxGrade = *++p;
38218616Sralph 				DEBUG(4, "MaxGrade set to %c\n", MaxGrade);
38318616Sralph 				break;
38423590Sbloom 			case 'v':
38523590Sbloom 				if (strncmp(p, "grade", 5) == 0) {
38623590Sbloom 					p += 6;
38723590Sbloom 					MaxGrade = DefMaxGrade = *p++;
38823590Sbloom 					DEBUG(4, "MaxGrade set to %c\n", MaxGrade);
38923590Sbloom 				}
39023590Sbloom 				break;
39113639Ssam 			default:
39213639Ssam 				break;
39313639Ssam 			}
39413639Ssam 			p = q;
39513639Ssam 		}
39613639Ssam 		if (callok(Rmtname) == SS_BADSEQ) {
39713639Ssam 			logent("BADSEQ", "PREVIOUS");
39813639Ssam 			omsg('R', "BADSEQ", Ofn);
39913639Ssam 			cleanup(0);
40013639Ssam 		}
40117767Sralph #ifdef GNXSEQ
40213639Ssam 		if ((ret = gnxseq(Rmtname)) == seq) {
40313639Ssam 			omsg('R', "OK", Ofn);
40413639Ssam 			cmtseq();
40517767Sralph 		} else {
40617767Sralph #else !GNXSEQ
40717767Sralph 		if (seq == 0)
40817767Sralph 			omsg('R', "OK", Ofn);
40913639Ssam 		else {
41017767Sralph #endif !GNXSEQ
41113639Ssam 			systat(Rmtname, Stattype[7], Stattext[7]);
41223590Sbloom 			logent("BAD SEQ", "FAILED HANDSHAKE");
41317767Sralph #ifdef GNXSEQ
41413639Ssam 			ulkseq();
41517767Sralph #endif GNXSEQ
41613639Ssam 			omsg('R', "BADSEQ", Ofn);
41713639Ssam 			cleanup(0);
41813639Ssam 		}
41913639Ssam 		ttyn = ttyname(Ifn);
42013639Ssam 		if (ttyn != NULL)
42113639Ssam 			chmod(ttyn, 0600);
42217767Sralph 	} else { /* Role == MASTER */
42317767Sralph 		struct stat stbuf;
42417767Sralph 		if (isatty(fileno(stderr)) || (fstat(fileno(stderr),&stbuf) == 0
42517767Sralph 		    && stbuf.st_mode&S_IFREG) )
42617767Sralph 			StdErrIsTty =  1;
42717767Sralph 		setdebug(0);
42813639Ssam 	}
42917767Sralph 
43013639Ssam loop:
43117767Sralph 	if(setjmp(Pipebuf)) {	/* come here on SIGPIPE	*/
43217767Sralph 		clsacu();
43317767Sralph 		close(Ofn);
43417767Sralph 		close(Ifn);
43517767Sralph 		Ifn = Ofn = -1;
43617767Sralph 		rmlock(CNULL);
43717767Sralph 		sleep(3);
43817767Sralph 	}
43913639Ssam 	if (!onesys) {
44017767Sralph 		struct stat sbuf;
44117767Sralph 
44217767Sralph 		if (!StdErrIsTty) {
44317767Sralph 			sprintf(file, "%s/%s", RMTDEBUG, Rmtname);
44417767Sralph 			if (stat(file, &sbuf) == 0 && sbuf.st_size == 0)
44517767Sralph 				unlink(file);
44617767Sralph 		}
44713639Ssam 		ret = gnsys(Rmtname, Spool, CMDPRE);
44817767Sralph 		setdebug(0);
44913639Ssam 		if (ret == FAIL)
45013639Ssam 			cleanup(100);
45123590Sbloom 		if (ret == SUCCESS)
45213639Ssam 			cleanup(0);
45317767Sralph 	} else if (Role == MASTER && callok(Rmtname) != 0) {
45413639Ssam 		logent("SYSTEM STATUS", "CAN NOT CALL");
45513639Ssam 		cleanup(0);
45613639Ssam 	}
45713639Ssam 
45823590Sbloom 	sprintf(wkpre, "%c.%.*s", CMDPRE, SYSNSIZE, Rmtname);
45913639Ssam 
46017767Sralph 	signal(SIGINT, SIG_IGN);
46117767Sralph 	signal(SIGQUIT, SIG_IGN);
46213639Ssam 	if (Role == MASTER) {
46317767Sralph 		/* check for /etc/nologin */
464*25124Sbloom 		if (access(NOLOGIN, 0) == 0) {
46517767Sralph 			logent(NOLOGIN, "UUCICO SHUTDOWN");
46623590Sbloom 			if (Debug > 4)
46717767Sralph 				logent("DEBUGGING", "continuing anyway");
46817767Sralph 			else
46917767Sralph 				cleanup(1);
47017767Sralph 		}
47113639Ssam 		/*  master part */
47213639Ssam 		signal(SIGHUP, SIG_IGN);
47313639Ssam 		if (Ifn != -1 && Role == MASTER) {
47413639Ssam 			write(Ofn, EOTMSG, strlen(EOTMSG));
47513639Ssam 			clsacu();
47613639Ssam 			close(Ofn);
47713639Ssam 			close(Ifn);
47813639Ssam 			Ifn = Ofn = -1;
47913639Ssam 			rmlock(CNULL);
48013639Ssam 			sleep(3);
48113639Ssam 		}
48213639Ssam 		sprintf(msg, "call to %s ", Rmtname);
483*25124Sbloom 		if (mlock(Rmtname) != SUCCESS) {
48413639Ssam 			logent(msg, "LOCKED");
48517767Sralph 			US_SST(us_s_lock);
48613639Ssam 			goto next;
48713639Ssam 		}
48813639Ssam 		Ofn = Ifn = conn(Rmtname);
48913639Ssam 		if (Ofn < 0) {
49017767Sralph 			if (Ofn != CF_TIME)
49117767Sralph 				logent(msg, _FAILED);
49217767Sralph 			/* avoid excessive 'wrong time' info */
49323590Sbloom 			if (Stattype[-Ofn] != SS_WRONGTIME){
49417767Sralph 				systat(Rmtname, Stattype[-Ofn], Stattext[-Ofn]);
49517767Sralph 				US_SST(-Ofn);
49617767Sralph 				UB_SST(-Ofn);
49717767Sralph 			}
49813639Ssam 			goto next;
49917767Sralph 		} else {
50013639Ssam 			logent(msg, "SUCCEEDED");
50117767Sralph 			US_SST(us_s_cok);
50217767Sralph 			UB_SST(ub_ok);
50313639Ssam 		}
50417767Sralph #ifdef	TCPIP
50517767Sralph 		/*
50617767Sralph 		 * Determine if we are on TCPIP
50717767Sralph 		 */
50817767Sralph 		if (isatty(Ifn) ==  0) {
50917767Sralph 			IsTcpIp = 1;
51017767Sralph 			DEBUG(4, "TCPIP connection -- ioctl-s disabled\n", CNULL);
51123590Sbloom 		} else
51223590Sbloom 			IsTcpIp = 0;
51317767Sralph #endif
51417767Sralph 
51513639Ssam 		if (setjmp(Sjbuf))
51613639Ssam 			goto next;
51713639Ssam 		signal(SIGALRM, timeout);
51813639Ssam 		alarm(2 * MAXMSGTIME);
51913639Ssam 		for (;;) {
52013639Ssam 			ret = imsg(msg, Ifn);
52113639Ssam 			if (ret != 0) {
52213639Ssam 				alarm(0);
52317767Sralph 				logent("imsg 1", _FAILED);
52417767Sralph 				goto Failure;
52513639Ssam 			}
52613639Ssam 			if (msg[0] == 'S')
52713639Ssam 				break;
52813639Ssam 		}
52913639Ssam 		alarm(MAXMSGTIME);
53017767Sralph #ifdef GNXSEQ
53113639Ssam 		seq = gnxseq(Rmtname);
53217767Sralph #else !GNXSEQ
53317767Sralph 		seq = 0;
53417767Sralph #endif !GNXSEQ
535*25124Sbloom 		if (Debug)
536*25124Sbloom 			sprintf(rflags, "-x%d", Debug);
537*25124Sbloom 		else
538*25124Sbloom 			rflags[0] = '\0';
539*25124Sbloom 
54018616Sralph 		if (MaxGrade != '\177') {
54123725Sbloom 			char buf[MAXFULLNAME];
54223590Sbloom 			sprintf(buf, " -p%c -vgrade=%c", MaxGrade, MaxGrade);
54318616Sralph 			strcat(rflags, buf);
54418616Sralph 		}
54518616Sralph 
54623590Sbloom 		sprintf(msg, "%s -Q%d %s", Myname, seq, rflags);
54723590Sbloom 		if (MaxGrade != '\177')
54823590Sbloom 			DEBUG(2, "Max Grade this transfer is %c\n", MaxGrade);
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 
59513639Ssam 	alarm(MAXMSGTIME);
59618616Sralph 	if (ret=setjmp(Sjbuf))
59713639Ssam 		goto Failure;
59813639Ssam 	ret = startup(Role);
59913639Ssam 	alarm(0);
60013639Ssam 	if (ret != SUCCESS) {
60117767Sralph 		logent("startup", _FAILED);
60213639Ssam Failure:
60317767Sralph 		US_SST(us_s_start);
60418616Sralph 		systat(Rmtname, SS_FAIL, ret > 0 ? "CONVERSATION FAILED" :
60518616Sralph 			"STARTUP FAILED");
60613639Ssam 		goto next;
60717767Sralph 	} else {
60813639Ssam 		logent("startup", "OK");
60917767Sralph 		US_SST(us_s_gress);
61013639Ssam 		systat(Rmtname, SS_INPROGRESS, "TALKING");
61113639Ssam 		ret = cntrl(Role, wkpre);
61213639Ssam 		DEBUG(1, "cntrl - %d\n", ret);
61313639Ssam 		signal(SIGINT, SIG_IGN);
61413639Ssam 		signal(SIGHUP, SIG_IGN);
61513639Ssam 		signal(SIGALRM, timeout);
61617767Sralph 		if (ret == SUCCESS) {
61713639Ssam 			logent("conversation complete", "OK");
61817767Sralph 			US_SST(us_s_ok);
61913639Ssam 			rmstat(Rmtname);
62013639Ssam 
62117767Sralph 		} else {
62217767Sralph 			logent("conversation complete", _FAILED);
62317767Sralph 			US_SST(us_s_cf);
62417767Sralph 			systat(Rmtname, SS_FAIL, "CONVERSATION FAILED");
62513639Ssam 		}
62613639Ssam 		alarm(MAXMSGTIME);
62713639Ssam 		DEBUG(4, "send OO %d,", ret);
62813639Ssam 		if (!setjmp(Sjbuf)) {
62913639Ssam 			for (;;) {
63013639Ssam 				omsg('O', "OOOOO", Ofn);
63113639Ssam 				ret = imsg(msg, Ifn);
63213639Ssam 				if (ret != 0)
63313639Ssam 					break;
63413639Ssam 				if (msg[0] == 'O')
63513639Ssam 					break;
63613639Ssam 			}
63713639Ssam 		}
63813639Ssam 		alarm(0);
63917767Sralph 		clsacu();
64017767Sralph 		rmlock(CNULL);
64113639Ssam 	}
64213639Ssam next:
64313639Ssam 	if (!onesys) {
64413639Ssam 		goto loop;
64513639Ssam 	}
64613639Ssam 	cleanup(0);
64713639Ssam }
64813639Ssam 
64917767Sralph #ifndef	USG
65013639Ssam struct sgttyb Hupvec;
65113639Ssam #endif
65213639Ssam 
65313639Ssam /***
65413639Ssam  *	cleanup(code)	cleanup and exit with "code" status
65513639Ssam  *	int code;
65613639Ssam  */
65713639Ssam 
65813639Ssam cleanup(code)
65913639Ssam register int code;
66013639Ssam {
66113639Ssam 	register char *ttyn;
66217767Sralph 	char bfr[BUFSIZ];
66317767Sralph 	struct stat sbuf;
66413639Ssam 
66513639Ssam 	signal(SIGINT, SIG_IGN);
66613639Ssam 	signal(SIGHUP, SIG_IGN);
66713639Ssam 	rmlock(CNULL);
66813639Ssam 	clsacu();
66913639Ssam 	logcls();
67013639Ssam 	if (Role == SLAVE) {
67117767Sralph 		if (!IsTcpIp) {
67217767Sralph #ifdef USG
67313639Ssam 			Savettyb.c_cflag |= HUPCL;
67423590Sbloom 			(void) ioctl(0, TCSETA, &Savettyb);
67517767Sralph #else !USG
67623590Sbloom 			(void) ioctl(0, TIOCHPCL, STBNULL);
67718616Sralph #ifdef TIOCSDTR
67823590Sbloom 			(void) ioctl(0, TIOCCDTR, STBNULL);
67918616Sralph 			sleep(2);
68023590Sbloom 			(void) ioctl(0, TIOCSDTR, STBNULL);
68118616Sralph #else !TIOCSDTR
68223590Sbloom 			(void) ioctl(0, TIOCGETP, &Hupvec);
68318616Sralph #endif !TIOCSDTR
68413639Ssam 			Hupvec.sg_ispeed = B0;
68513639Ssam 			Hupvec.sg_ospeed = B0;
68623590Sbloom 			(void) ioctl(0, TIOCSETP, &Hupvec);
68713639Ssam 			sleep(2);
68823590Sbloom 			(void) ioctl(0, TIOCSETP, &Savettyb);
68917767Sralph 			/* make *sure* exclusive access is off */
69023590Sbloom 			(void) ioctl(0, TIOCNXCL, STBNULL);
69117767Sralph #endif !USG
69213639Ssam 		}
69313639Ssam 		ttyn = ttyname(Ifn);
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);
71117767Sralph 	sprintf(bfr, "%s/%s", RMTDEBUG, Rmtname);
71217767Sralph 	if (stat(bfr, &sbuf) == 0 && sbuf.st_size == 0)
71317767Sralph 		unlink(bfr);
71417767Sralph 	sprintf(bfr, "%s/%d", RMTDEBUG, getpid());
71517767Sralph 	unlink(bfr);
71613639Ssam 	exit(code);
71713639Ssam }
71813639Ssam 
71913639Ssam /***
72013639Ssam  *	onintr(inter)	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  */
74317767Sralph setdebug(code)
74417767Sralph int code;
74513639Ssam {
74617767Sralph 	char buf[BUFSIZ];
74717767Sralph 
74823590Sbloom 	if (code) {
74923590Sbloom 		if (Debug == 0)
75023590Sbloom 			Debug = 30;
75123590Sbloom 		else
75223590Sbloom 			Debug = 0;
75323590Sbloom 	}
75423590Sbloom 	if (Debug && !StdErrIsTty) {
75517767Sralph 		sprintf(buf,"%s/%s", RMTDEBUG, Rmtname);
75617767Sralph 		unlink(buf);
75717767Sralph 		freopen(buf, "w", stderr);
75817767Sralph #ifdef BSD4_2
75917767Sralph 		setlinebuf(stderr);
76017767Sralph #else  !BSD4_2
76117767Sralph 		setbuf(stderr, NULL);
76217767Sralph #endif !BSD4_2
76317767Sralph 	}
76413639Ssam }
76513639Ssam 
76613639Ssam 
76713639Ssam /***
76813639Ssam  *	fixmode(tty)	fix kill/echo/raw on line
76913639Ssam  *
77013639Ssam  *	return codes:  none
77113639Ssam  */
77213639Ssam 
77313639Ssam fixmode(tty)
77413639Ssam register int tty;
77513639Ssam {
77617767Sralph #ifdef	USG
77713639Ssam 	struct termio ttbuf;
77813639Ssam #endif
77917767Sralph #ifndef	USG
78013639Ssam 	struct sgttyb ttbuf;
78113639Ssam #endif
78213639Ssam 
78317767Sralph 	if (IsTcpIp)
78413639Ssam 		return;
78517767Sralph #ifdef	USG
78623590Sbloom 	ioctl(tty, TCGETA, &ttbuf);
78713639Ssam 	ttbuf.c_iflag = ttbuf.c_oflag = ttbuf.c_lflag = (ushort)0;
78813639Ssam 	ttbuf.c_cflag &= (CBAUD);
78913639Ssam 	ttbuf.c_cflag |= (CS8|CREAD);
79013639Ssam 	ttbuf.c_cc[VMIN] = 6;
79113639Ssam 	ttbuf.c_cc[VTIME] = 1;
79223590Sbloom 	ioctl(tty, TCSETA, &ttbuf);
79313639Ssam #endif
79417767Sralph #ifndef	USG
79513639Ssam 	ioctl(tty, TIOCGETP, &ttbuf);
79613639Ssam 	ttbuf.sg_flags = (ANYP | RAW);
79723590Sbloom 	ioctl(tty, TIOCSETP, &ttbuf);
79813639Ssam #endif
79917767Sralph #ifndef	USG
80023590Sbloom 	ioctl(tty, TIOCEXCL, STBNULL);
80113639Ssam #endif
80213639Ssam }
80313639Ssam 
80413639Ssam 
80523590Sbloom /*
80613639Ssam  *	timeout()	catch SIGALRM routine
80713639Ssam  */
80813639Ssam 
80913639Ssam timeout()
81013639Ssam {
81123590Sbloom 	extern int HaveSentHup;
81223590Sbloom 	if (!HaveSentHup) {
81323590Sbloom 		logent(Rmtname, "TIMEOUT");
81423590Sbloom 		if (*Rmtname && strncmp(Rmtname, Myname, MAXBASENAME)) {
81523590Sbloom 			US_SST(us_s_tmot);
81623590Sbloom 			systat(Rmtname, SS_FAIL, "TIMEOUT");
81723590Sbloom 		}
81817767Sralph 	}
81913639Ssam 	longjmp(Sjbuf, 1);
82013639Ssam }
82113639Ssam 
82213639Ssam static char *
82313639Ssam pskip(p)
82413639Ssam register char *p;
82513639Ssam {
82617767Sralph 	while(*p && *p != ' ')
82713639Ssam 		++p;
82823590Sbloom 	while(*p && *p == ' ')
82917767Sralph 		*p++ = 0;
83017767Sralph 	return p;
83113639Ssam }
832