xref: /original-bsd/usr.bin/uucp/uucico/cico.c (revision 53530174)
1 #ifndef lint
2 static char sccsid[] = "@(#)cico.c	5.15 (Berkeley) 02/24/88";
3 #endif
4 
5 #include <signal.h>
6 #include "uucp.h"
7 #include <setjmp.h>
8 #ifdef	USG
9 #include <termio.h>
10 #include <fcntl.h>
11 #endif
12 #ifndef	USG
13 #include <sgtty.h>
14 #endif
15 #ifdef BSDTCP
16 #include <netdb.h>
17 #include <netinet/in.h>
18 #include <sys/socket.h>
19 #endif BSDTCP
20 #include <sys/stat.h>
21 #ifdef BSD4_2
22 #include <sys/time.h>
23 #include <fcntl.h>
24 #else
25 #include <time.h>
26 #endif
27 #include "uust.h"
28 #include "uusub.h"
29 
30 #if defined(VMS) && defined(BSDTCP)
31 #define NOGETPEER
32 #endif
33 
34 #ifdef BSD2_9
35 #define NOGETPEER
36 #endif
37 
38 jmp_buf Sjbuf;
39 jmp_buf Pipebuf;
40 
41 /*  call fail text  */
42 char *Stattext[] = {
43 	"",
44 	"BAD SYSTEM",
45 	"WRONG TIME TO CALL",
46 	"SYSTEM LOCKED",
47 	"NO DEVICE",
48 	"CALL FAILED",
49 	"LOGIN FAILED",
50 	"BAD SEQUENCE"
51 };
52 
53 /*  call fail codes  */
54 int Stattype[] = {
55 	0,
56 	0,
57 	SS_WRONGTIME,
58 	0,
59 	SS_NODEVICE,
60 	SS_FAIL,
61 	SS_FAIL,
62 	SS_BADSEQ
63 };
64 
65 				/* Arguments to setdebug():		     */
66 #define DBG_TEMP  0		/*   Create a temporary audit file	     */
67 #define DBG_PERM  1		/*   Create a permanent audit file	     */
68 #define DBG_CLEAN 2		/*   Cleanup, discard temp file		     */
69 
70 int ReverseRole = 0;
71 int Role = SLAVE;
72 int InitialRole = SLAVE;
73 long StartTime;
74 int onesys = 0;
75 int turntime = 30 * 60;	/* 30 minutes expressed in seconds */
76 char *ttyn = NULL;
77 extern int LocalOnly;
78 extern int errno;
79 extern char MaxGrade, DefMaxGrade;
80 extern char Myfullname[];
81 
82 long Bytes_Sent, Bytes_Received;
83 
84 #ifdef	USG
85 struct termio Savettyb;
86 #endif
87 #ifndef	USG
88 struct sgttyb Savettyb;
89 #endif
90 
91 /*
92  *	this program is used  to place a call to a
93  *	remote machine, login, and copy files between the two machines.
94  */
95 main(argc, argv)
96 int argc;
97 register char *argv[];
98 {
99 	register int ret;
100 	int seq;
101 	char wkpre[NAMESIZE], file[NAMESIZE];
102 	char msg[MAXFULLNAME], *q;
103 	register char *p;
104 	extern onintr(), timeout(), dbg_signal();
105 	extern char *pskip();
106 	char rflags[MAXFULLNAME];
107 #ifdef NOGETPEER
108 	u_long Hostnumber = 0;
109 #endif NOGETPEER
110 
111 	strcpy(Progname, "uucico");
112 
113 #ifdef BSD4_2
114 	sigsetmask(0);	/* in case we inherit blocked signals */
115 #endif BSD4_2
116 	signal(SIGINT, onintr);
117 	signal(SIGHUP, onintr);
118 	signal(SIGQUIT, onintr);
119 	signal(SIGTERM, onintr);
120 	signal(SIGPIPE, onintr);	/* 4.1a tcp-ip stupidity */
121 	signal(SIGFPE, dbg_signal);
122 	ret = guinfo(getuid(), User, msg);
123 	strcpy(Loginuser, User);
124 	uucpname(Myname);
125 	ASSERT(ret == 0, "BAD UID", CNULL, ret);
126 
127 	setbuf (stderr, CNULL);
128 
129 	rflags[0] = '\0';
130 	umask(WFMASK);
131 	strcpy(Rmtname, Myname);
132 	Ifn = Ofn = -1;
133 	while(argc>1 && argv[1][0] == '-'){
134 		switch(argv[1][1]){
135 		case 'd':
136 			Spool = &argv[1][2];
137 			break;
138 		case 'g':
139 		case 'p':
140 			MaxGrade = DefMaxGrade = argv[1][2];
141 			break;
142 		case 'r':
143 			Role = atoi(&argv[1][2]);
144 			break;
145 		case 'R':
146 			ReverseRole++;
147 			Role = MASTER;
148 			break;
149 		case 's':
150 			strncpy(Rmtname, &argv[1][2], MAXBASENAME);
151 			Rmtname[MAXBASENAME] = '\0';
152 			if (Rmtname[0] != '\0')
153 				onesys = 1;
154 			break;
155 		case 'x':
156 			Debug = atoi(&argv[1][2]);
157 			if (Debug <= 0)
158 				Debug = 1;
159 			strcat(rflags, argv[1]);
160 			break;
161 		case 't':
162 			turntime = atoi(&argv[1][2])*60;/* minutes to seconds */
163 			break;
164 		case 'L':	/* local calls only */
165 			LocalOnly++;
166 			break;
167 #ifdef NOGETPEER
168 		case 'h':
169 			Hostnumber = inet_addr(&argv[1][2]);
170 			break;
171 #endif NOGETPEER
172 		default:
173 			printf("unknown flag %s (ignored)\n", argv[1]);
174 			break;
175 		}
176 		--argc;  argv++;
177 	}
178 
179 	while (argc > 1) {
180 		fprintf(stderr, "unknown argument %s (ignored)\n", argv[1]);
181 		--argc; argv++;
182 	}
183 
184 	if (Debug && Role == MASTER)
185 		chkdebug();
186 
187 	/* Try to run as uucp */
188 	setgid(getegid());
189 	setuid(geteuid());
190 #ifdef	TIOCNOTTY
191 	/*
192 	 * detach uucico from controlling terminal
193 	 * to defend against rlogind sending us a SIGKILL (!!!)
194 	 */
195 	if (Role == MASTER && (ret = open("/dev/tty", 2)) >= 0) {
196 		ioctl(ret, TIOCNOTTY, STBNULL);
197 		close(ret);
198 	}
199 #endif TIOCNOTTY
200 #ifdef BSD4_2
201 	if (getpgrp(0) == 0) { /* We have no controlling terminal */
202 		setpgrp(0, getpid());
203 	}
204 #endif BSD4_2
205 
206 	ret = subchdir(Spool);
207 	ASSERT(ret >= 0, "CHDIR FAILED", Spool, ret);
208 	strcpy(Wrkdir, Spool);
209 
210 	if (Debug) {
211 		setdebug ((Role == SLAVE) ? DBG_TEMP : DBG_PERM);
212 		if (Debug > 0)
213 			logent ("Local Enabled", "DEBUG");
214 	}
215 
216 	/*
217 	 * First time through: If we're the slave, do initial checking.
218 	 */
219 	if (Role == SLAVE) {
220 		/* check for /etc/nologin */
221 		if (access(NOLOGIN, 0) == 0) {
222 			logent(NOLOGIN, "UUCICO SHUTDOWN");
223 			if (Debug > 4)
224 				logent("DEBUGGING", "continuing anyway");
225 			else
226 				cleanup(1);
227 		}
228 		Ifn = 0;
229 		Ofn = 1;
230 #ifdef	TCPIP
231 		/*
232 		 * Determine if we are on TCPIP
233 		 */
234 		if (isatty(Ifn) == 0) {
235 			IsTcpIp = 1;
236 			DEBUG(4, "TCPIP connection -- ioctl-s disabled\n", CNULL);
237 		} else
238 			IsTcpIp = 0;
239 #endif TCPIP
240 		/* initial handshake */
241 		onesys = 1;
242 		if (!IsTcpIp) {
243 #ifdef	USG
244 			ret = ioctl(Ifn, TCGETA, &Savettyb);
245 			Savettyb.c_cflag = (Savettyb.c_cflag & ~CS8) | CS7;
246 			Savettyb.c_oflag |= OPOST;
247 			Savettyb.c_lflag |= (ISIG|ICANON|ECHO);
248 #else !USG
249 			ret = ioctl(Ifn, TIOCGETP, &Savettyb);
250 			Savettyb.sg_flags |= ECHO;
251 			Savettyb.sg_flags &= ~RAW;
252 #endif !USG
253 			ttyn = ttyname(Ifn);
254 		}
255 		fixmode(Ifn);
256 
257 		/*
258 		 * Initial Message -- tell them we're here, and who we are.
259 		 */
260 		sprintf(msg, "here=%s", Myfullname);
261 		omsg('S', msg, Ofn);
262 		signal(SIGALRM, timeout);
263 		alarm(IsTcpIp?MAXMSGTIME*4:MAXMSGTIME);
264 		if (setjmp(Sjbuf)) {
265 			/* timed out */
266 			if (!IsTcpIp) {
267 #ifdef	USG
268 				ret = ioctl(Ifn, TCSETA, &Savettyb);
269 
270 #else	!USG
271 				ret = ioctl(Ifn, TIOCSETP, &Savettyb);
272 #endif !USG
273 			}
274 			cleanup(0);
275 		}
276 		for (;;) {
277 			ret = imsg(msg, Ifn);
278 			if (ret != SUCCESS) {
279 				alarm(0);
280 				if (!IsTcpIp) {
281 #ifdef	USG
282 					ret = ioctl(Ifn, TCSETA, &Savettyb);
283 #else	!USG
284 					ret = ioctl(Ifn, TIOCSETP, &Savettyb);
285 #endif !USG
286 				}
287 				cleanup(0);
288 			}
289 			if (msg[0] == 'S')
290 				break;
291 		}
292 		alarm(0);
293 		q = &msg[1];
294 		p = pskip(q);
295 		strncpy(Rmtname, q, MAXBASENAME);
296 		Rmtname[MAXBASENAME] = '\0';
297 
298 		/*
299 		 * Now that we know who they are, give the audit file the right
300 		 * name.
301 		 */
302 		setdebug (DBG_PERM);
303 		DEBUG(4, "sys-%s\n", Rmtname);
304 		/* The versys will also do an alias on the incoming name */
305 		if (versys(&Rmtname)) {
306 #ifdef	NOSTRANGERS
307 			/* If we don't know them, we won't talk to them... */
308 			assert("Unknown host:", Rmtname, 0);
309 			omsg('R', "You are unknown to me", Ofn);
310 			cleanup(0);
311 #endif	NOSTRANGERS
312 		}
313 #ifdef BSDTCP
314 		/* we must make sure they are really who they say they
315 		 * are. We compare the hostnumber with the number in the hosts
316 		 * table for the site they claim to be.
317 		 */
318 		if (IsTcpIp) {
319 			struct hostent *hp;
320 			char *cpnt, *inet_ntoa();
321 			int fromlen;
322 			struct sockaddr_in from;
323 			extern char PhoneNumber[];
324 
325 #ifdef	NOGETPEER
326 			from.sin_addr.s_addr = Hostnumber;
327 			from.sin_family = AF_INET;
328 #else	!NOGETPEER
329 			fromlen = sizeof(from);
330 			if (getpeername(Ifn, &from, &fromlen) < 0) {
331 				logent(Rmtname, "NOT A TCP CONNECTION");
332 				omsg('R', "NOT TCP", Ofn);
333 				cleanup(0);
334 			}
335 #endif	!NOGETPEER
336 			hp = gethostbyaddr(&from.sin_addr,
337 				sizeof (struct in_addr), from.sin_family);
338 			if (hp == NULL) {
339 				/* security break or just old host table? */
340 				logent(Rmtname, "UNKNOWN IP-HOST Name =");
341 				cpnt = inet_ntoa(from.sin_addr),
342 				logent(cpnt, "UNKNOWN IP-HOST Number =");
343 				sprintf(wkpre, "%s/%s isn't in my host table",
344 					Rmtname, cpnt);
345 				omsg('R' ,wkpre ,Ofn);
346 				cleanup(0);
347 			}
348 			if (Debug > 99)
349 				logent(Rmtname,"Request from IP-Host name =");
350 			/*
351 			 * The following is to determine if the name given us by
352 			 * the Remote uucico matches any of the names
353 			 * given its network number (remote machine) in our
354 			 * host table.
355 			 * We could check the aliases, but that won't work in
356 			 * all cases (like if you are running the domain
357 			 * server, where you don't get any aliases). The only
358 			 * reliable way I can think of that works in ALL cases
359 			 * is too look up the site in L.sys and see if the
360 			 * sitename matches what we would call him if we
361 			 * originated the call.
362 			 */
363 			/* PhoneNumber contains the official network name of the 			   host we are checking. (set in versys.c) */
364 			if (sncncmp(PhoneNumber, hp->h_name, SYSNSIZE) == 0) {
365 				if (Debug > 99)
366 					logent(q,"Found in host Tables");
367 			} else {
368 				logent(hp->h_name, "FORGED HOSTNAME");
369 				logent(inet_ntoa(from.sin_addr), "ORIGINATED AT");
370 				logent(PhoneNumber, "SHOULD BE");
371 				sprintf(wkpre, "You're not who you claim to be: %s !=  %s", hp->h_name, PhoneNumber);
372 				omsg('R', wkpre, Ofn);
373 				cleanup(0);
374 			}
375 		}
376 #endif	BSDTCP
377 
378 		if (mlock(Rmtname)) {
379 			omsg('R', "LCK", Ofn);
380 			cleanup(0);
381 		}
382 		else if (callback(Loginuser)) {
383 			signal(SIGINT, SIG_IGN);
384 			signal(SIGHUP, SIG_IGN);
385 			omsg('R', "CB", Ofn);
386 			logent("CALLBACK", "REQUIRED");
387 			/*  set up for call back  */
388 			systat(Rmtname, SS_CALLBACK, "CALLING BACK");
389 			gename(CMDPRE, Rmtname, 'C', file);
390 			close(creat(subfile(file), 0666));
391 			xuucico(Rmtname);
392 			cleanup(0);
393 		}
394 		seq = 0;
395 		while (*p == '-') {
396 			q = pskip(p);
397 			switch(*(++p)) {
398 			case 'x':
399 				if (Debug == 0) {
400 					Debug = atoi(++p);
401 					if (Debug <= 0)
402 						Debug = 1;
403 					setdebug(DBG_PERM);
404 					if (Debug > 0)
405 						logent("Remote Enabled", "DEBUG");
406 				} else {
407 					DEBUG(1, "Remote debug request ignored\n",
408 					   CNULL);
409 				}
410 				break;
411 			case 'Q':
412 				seq = atoi(++p);
413 				break;
414 			case 'p':
415 				MaxGrade = DefMaxGrade = *++p;
416 				DEBUG(4, "MaxGrade set to %c\n", MaxGrade);
417 				break;
418 			case 'v':
419 				if (strncmp(p, "grade", 5) == 0) {
420 					p += 6;
421 					MaxGrade = DefMaxGrade = *p++;
422 					DEBUG(4, "MaxGrade set to %c\n", MaxGrade);
423 				}
424 				break;
425 			default:
426 				break;
427 			}
428 			p = q;
429 		}
430 		if (callok(Rmtname) == SS_BADSEQ) {
431 			logent("BADSEQ", "PREVIOUS");
432 			omsg('R', "BADSEQ", Ofn);
433 			cleanup(0);
434 		}
435 #ifdef GNXSEQ
436 		if ((ret = gnxseq(Rmtname)) == seq) {
437 			omsg('R', "OK", Ofn);
438 			cmtseq();
439 		} else {
440 #else !GNXSEQ
441 		if (seq == 0)
442 			omsg('R', "OK", Ofn);
443 		else {
444 #endif !GNXSEQ
445 			systat(Rmtname, Stattype[7], Stattext[7]);
446 			logent("BAD SEQ", "FAILED HANDSHAKE");
447 #ifdef GNXSEQ
448 			ulkseq();
449 #endif GNXSEQ
450 			omsg('R', "BADSEQ", Ofn);
451 			cleanup(0);
452 		}
453 		if (ttyn != NULL)
454 			chmod(ttyn, 0600);
455 	}
456 
457 loop:
458 	if(setjmp(Pipebuf)) {	/* come here on SIGPIPE	*/
459 		clsacu();
460 		close(Ofn);
461 		close(Ifn);
462 		Ifn = Ofn = -1;
463 		rmlock(CNULL);
464 		sleep(3);
465 	}
466 	if (!onesys) {
467 		do_connect_accounting();
468 		StartTime = 0;
469 		ret = gnsys(Rmtname, Spool, CMDPRE);
470 		setdebug(DBG_PERM);
471 		if (ret == FAIL)
472 			cleanup(100);
473 		else if (ret == SUCCESS)
474 			cleanup(0);
475 	} else if (Role == MASTER && callok(Rmtname) != 0) {
476 		logent("SYSTEM STATUS", "CAN NOT CALL");
477 		cleanup(0);
478 	}
479 
480 	sprintf(wkpre, "%c.%.*s", CMDPRE, SYSNSIZE, Rmtname);
481 	StartTime = 0;
482 	Bytes_Sent = Bytes_Received = 0L;
483 
484 	signal(SIGINT, SIG_IGN);
485 	signal(SIGQUIT, SIG_IGN);
486 	if (Role == MASTER) {
487 		extern char LineType[];
488 		/* check for /etc/nologin */
489 		if (access(NOLOGIN, 0) == 0) {
490 			logent(NOLOGIN, "UUCICO SHUTDOWN");
491 			if (Debug > 4)
492 				logent("DEBUGGING", "continuing anyway");
493 			else
494 				cleanup(1);
495 		}
496 		/*  master part */
497 		signal(SIGHUP, SIG_IGN);
498 		if (Ifn != -1 && Role == MASTER) {
499 			write(Ofn, EOTMSG, strlen(EOTMSG));
500 			clsacu();
501 			close(Ofn);
502 			close(Ifn);
503 			Ifn = Ofn = -1;
504 			rmlock(CNULL);
505 			sleep(3);
506 		}
507 		if (mlock(Rmtname) != SUCCESS) {
508 			DEBUG(1, "LOCKED: call to %s\n", Rmtname);
509 			US_SST(us_s_lock);
510 			goto next;
511 		}
512 		Ofn = Ifn = conn(Rmtname);
513 		sprintf(msg, "call to %s via %s", Rmtname, LineType);
514 		if (Ofn < 0) {
515 			if (Ofn != CF_TIME)
516 				logent(msg, _FAILED);
517 			/* avoid excessive 'wrong time' info */
518 			if (Stattype[-Ofn] != SS_WRONGTIME){
519 				systat(Rmtname, Stattype[-Ofn], Stattext[-Ofn]);
520 				US_SST(-Ofn);
521 				UB_SST(-Ofn);
522 			}
523 			goto next;
524 		} else {
525 			logent(msg, "SUCCEEDED");
526 			US_SST(us_s_cok);
527 			UB_SST(ub_ok);
528 		}
529 		InitialRole = MASTER;
530 #ifdef	TCPIP
531 		/*
532 		 * Determine if we are on TCPIP
533 		 */
534 		if (isatty(Ifn) == 0) {
535 			IsTcpIp = 1;
536 			DEBUG(4, "TCPIP connection -- ioctl-s disabled\n", CNULL);
537 		} else
538 			IsTcpIp = 0;
539 #endif
540 
541 		if (setjmp(Sjbuf))
542 			goto next;
543 		signal(SIGALRM, timeout);
544 		alarm(IsTcpIp?MAXMSGTIME*4:MAXMSGTIME*2);
545 		for (;;) {
546 			ret = imsg(msg, Ifn);
547 			if (ret != SUCCESS) {
548 				alarm(0);
549 				DEBUG(4,"\nimsg failed: errno %d\n", errno);
550 				logent("imsg 1", _FAILED);
551 				goto Failure;
552 			}
553 			if (msg[0] == 'S')
554 				break;
555 		}
556 		alarm(IsTcpIp?MAXMSGTIME*4:MAXMSGTIME);
557 #ifdef GNXSEQ
558 		seq = gnxseq(Rmtname);
559 #else !GNXSEQ
560 		seq = 0;
561 #endif !GNXSEQ
562 		if (MaxGrade != '\177') {
563 			DEBUG(2, "Max Grade this transfer is %c\n", MaxGrade);
564 			sprintf(msg, "%s -Q%d -p%c -vgrade=%c %s",
565 				Myname, seq, MaxGrade, MaxGrade, rflags);
566 		} else
567 			sprintf(msg, "%s -Q%d %s", Myname, seq, rflags);
568 		omsg('S', msg, Ofn);
569 		for (;;) {
570 			ret = imsg(msg, Ifn);
571 			DEBUG(4, "msg-%s\n", msg);
572 			if (ret != SUCCESS) {
573 				alarm(0);
574 #ifdef GNXSEQ
575 				ulkseq();
576 #endif GNXSEQ
577 				logent("imsg 2", _FAILED);
578 				goto Failure;
579 			}
580 			if (msg[0] == 'R')
581 				break;
582 		}
583 		alarm(0);
584 		if (msg[1] == 'B') {
585 			/* bad sequence */
586 			logent("BAD SEQ", "FAILED HANDSHAKE");
587 			US_SST(us_s_hand);
588 			systat(Rmtname, SS_BADSEQ, Stattext[SS_BADSEQ]);
589 #ifdef GNXSEQ
590 			ulkseq();
591 #endif GNXSEQ
592 			goto next;
593 		}
594 		if (strcmp(&msg[1], "OK") != SAME)  {
595 			logent(&msg[1], "FAILED HANDSHAKE");
596 			US_SST(us_s_hand);
597 #ifdef GNXSEQ
598 			ulkseq();
599 #endif GNXSEQ
600 			systat(Rmtname, SS_INPROGRESS,
601 				strcmp(&msg[1], "CB") == SAME?
602 				"AWAITING CALLBACK": "FAILED HANDSHAKE");
603 			goto next;
604 		}
605 #ifdef GNXSEQ
606 		cmtseq();
607 #endif GNXSEQ
608 	}
609 	DEBUG(1, "Rmtname %s, ", Rmtname);
610 	DEBUG(1, "Role %s,  ", Role ? "MASTER" : "SLAVE");
611 	DEBUG(1, "Ifn - %d, ", Ifn);
612 	DEBUG(1, "Loginuser - %s\n", Loginuser);
613 
614 	ttyn = ttyname(Ifn);
615 
616 	alarm(IsTcpIp?MAXMSGTIME*4:MAXMSGTIME);
617 	if (ret=setjmp(Sjbuf))
618 		goto Failure;
619 	ret = startup(Role);
620 	alarm(0);
621 	if (ret != SUCCESS) {
622 		logent("startup", _FAILED);
623 Failure:
624 		US_SST(us_s_start);
625 		systat(Rmtname, SS_FAIL, ret > 0 ? "CONVERSATION FAILED" :
626 			"STARTUP FAILED");
627 		goto next;
628 	} else {
629 		char smsg[BUFSIZ], gmsg[10], pmsg[20], bpsmsg[20];
630 		extern char UsingProtocol;
631 		extern int linebaudrate;
632 		if (ttyn != NULL)
633 			sprintf(bpsmsg, " %s %d bps", &ttyn[5], linebaudrate);
634 		else
635 			bpsmsg[0] = '\0';
636 		if (UsingProtocol != 'g')
637 			sprintf(pmsg, " %c protocol", UsingProtocol);
638 		else
639 			pmsg[0] = '\0';
640 		if (MaxGrade != '\177')
641 			sprintf(gmsg, " grade %c", MaxGrade);
642 		else
643 			gmsg[0] = '\0';
644 		sprintf(smsg, "startup%s%s%s", bpsmsg, pmsg, gmsg);
645 		logent(smsg, "OK");
646 		US_SST(us_s_gress);
647 		StartTime = Now.time;
648 		systat(Rmtname, SS_INPROGRESS, "TALKING");
649 		ret = cntrl(Role, wkpre);
650 		DEBUG(1, "cntrl - %d\n", ret);
651 		signal(SIGINT, SIG_IGN);
652 		signal(SIGHUP, SIG_IGN);
653 		signal(SIGALRM, timeout);
654 		sprintf(smsg, "conversation complete %ld sent %ld received",
655 			Bytes_Sent, Bytes_Received);
656 		if (ret == SUCCESS) {
657 			logent(smsg, "OK");
658 			US_SST(us_s_ok);
659 			rmstat(Rmtname);
660 
661 		} else {
662 			logent(smsg, _FAILED);
663 			US_SST(us_s_cf);
664 			systat(Rmtname, SS_FAIL, "CONVERSATION FAILED");
665 		}
666 		alarm(IsTcpIp?MAXMSGTIME*4:MAXMSGTIME);
667 		DEBUG(4, "send OO %d,", ret);
668 		if (!setjmp(Sjbuf)) {
669 			for (;;) {
670 				omsg('O', "OOOOO", Ofn);
671 				ret = imsg(msg, Ifn);
672 				if (ret != 0)
673 					break;
674 				if (msg[0] == 'O')
675 					break;
676 			}
677 		}
678 		alarm(0);
679 		clsacu();
680 		rmlock(CNULL);
681 
682 	}
683 next:
684 	if (!onesys) {
685 		goto loop;
686 	}
687 	cleanup(0);
688 }
689 
690 #ifndef	USG
691 struct sgttyb Hupvec;
692 #endif
693 
694 /*
695  *	cleanup and exit with "code" status
696  */
697 cleanup(code)
698 register int code;
699 {
700 	signal(SIGINT, SIG_IGN);
701 	signal(SIGHUP, SIG_IGN);
702 	rmlock(CNULL);
703 	sleep(5);			/* Wait for any pending output	  */
704 	clsacu();
705 	logcls();
706 	if (Role == SLAVE) {
707 		if (!IsTcpIp) {
708 #ifdef USG
709 			Savettyb.c_cflag |= HUPCL;
710 			(void) ioctl(0, TCSETA, &Savettyb);
711 #else !USG
712 			(void) ioctl(0, TIOCHPCL, STBNULL);
713 #ifdef TIOCSDTR
714 			(void) ioctl(0, TIOCCDTR, STBNULL);
715 			sleep(2);
716 			(void) ioctl(0, TIOCSDTR, STBNULL);
717 #else !TIOCSDTR
718 			(void) ioctl(0, TIOCGETP, &Hupvec);
719 			Hupvec.sg_ispeed = B0;
720 			Hupvec.sg_ospeed = B0;
721 			(void) ioctl(0, TIOCSETP, &Hupvec);
722 #endif !TIOCSDTR
723 			sleep(2);
724 			(void) ioctl(0, TIOCSETP, &Savettyb);
725 			/* make *sure* exclusive access is off */
726 			(void) ioctl(0, TIOCNXCL, STBNULL);
727 #endif !USG
728 		}
729 		if (ttyn != NULL)
730 			chmod(ttyn, 0600);
731 	}
732 	if (Ofn != -1) {
733 		if (Role == MASTER)
734 			write(Ofn, EOTMSG, strlen(EOTMSG));
735 		close(Ifn);
736 		close(Ofn);
737 	}
738 #ifdef DIALINOUT
739 	/* reenable logins on dialout */
740 	reenable();
741 #endif DIALINOUT
742 	if (code == 0)
743 		xuuxqt();
744 	else
745 		DEBUG(1, "exit code %d\n", code);
746 	setdebug (DBG_CLEAN);
747 	do_connect_accounting();
748 	exit(code);
749 }
750 
751 do_connect_accounting()
752 {
753 	register FILE *fp;
754 	struct tm *localtime();
755 	register struct tm *tm;
756 	int flags;
757 
758 	if (StartTime == 0)
759 		return;
760 
761 #ifdef DO_CONNECT_ACCOUNTING
762 	fp = fopen("/usr/spool/uucp/CONNECT", "a");
763 	ASSERT(fp != NULL, "Can't open CONNECT file", Rmtname, errno);
764 
765 	tm = localtime(&StartTime);
766 #ifdef F_SETFL
767 	flags = fcntl(fileno(fp), F_GETFL, 0);
768 	fcntl(fileno(fp), F_SETFL, flags|O_APPEND);
769 #endif
770 #ifdef USG
771 	fprintf(fp,"%s %d %d%.2d%.2d %.2d%.2d %d %ld %s %ld %ld\n",
772 #else /* V7 */
773 	fprintf(fp,"%s %d %d%02d%02d %02d%02d %d %ld %s %ld %ld\n",
774 #endif /* V7 */
775 		Rmtname, InitialRole, tm->tm_year, tm->tm_mon + 1,
776 		tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_wday,
777 		(Now.time - StartTime + 59) / 60,
778 		ttyn == NULL ? "ttyp0" : &ttyn[5],
779 			Bytes_Sent, Bytes_Received);
780 	fclose(fp);
781 #endif /* DO_CONNECT_ACCOUNTING */
782 }
783 
784 /*
785  *	on interrupt - remove locks and exit
786  */
787 
788 onintr(inter)
789 register int inter;
790 {
791 	char str[BUFSIZ];
792 	signal(inter, SIG_IGN);
793 	sprintf(str, "SIGNAL %d", inter);
794 	logent(str, "CAUGHT");
795 	US_SST(us_s_intr);
796 	if (*Rmtname && strncmp(Rmtname, Myname, MAXBASENAME))
797 		systat(Rmtname, SS_FAIL, str);
798 	sprintf(str, "conversation complete %ld sent %ld received",
799 		Bytes_Sent, Bytes_Received);
800 	logent(str, _FAILED);
801 	if (inter == SIGPIPE && !onesys)
802 		longjmp(Pipebuf, 1);
803 	cleanup(inter);
804 }
805 
806 /*
807  * Catch a special signal
808  * (SIGFPE, ugh), and toggle debugging between 0 and 30.
809  * Handy for looking in on long running uucicos.
810  */
811 dbg_signal()
812 {
813 	Debug = (Debug == 0) ? 30 : 0;
814 	setdebug(DBG_PERM);
815 	if (Debug > 0)
816 		logent("Signal Enabled", "DEBUG");
817 }
818 
819 
820 /*
821  * Check debugging requests, and open RMTDEBUG audit file if necessary. If an
822  * audit file is needed, the parm argument indicates how to create the file:
823  *
824  *	DBG_TEMP  - Open a temporary file, with filename = RMTDEBUG/pid.
825  *	DBG_PERM  - Open a permanent audit file, filename = RMTDEBUG/Rmtname.
826  *		    If a temp file already exists, it is mv'ed to be permanent.
827  *	DBG_CLEAN - Cleanup; unlink temp files.
828  *
829  * Restrictions - this code can only cope with one open debug file at a time.
830  * Each call creates a new file; if an old one of the same name exists it will
831  * be overwritten.
832  */
833 setdebug(parm)
834 int parm;
835 {
836 	char buf[BUFSIZ];		/* Buffer for building filenames     */
837 	static char *temp = NULL;	/* Ptr to temporary file name	     */
838 	static int auditopen = 0;	/* Set to 1 when we open a file	     */
839 	struct stat stbuf;		/* File status buffer		     */
840 
841 	/*
842 	 * If movement or cleanup of a temp file is indicated, we do it no
843 	 * matter what.
844 	 */
845 	if (temp != CNULL && parm == DBG_PERM) {
846 		sprintf(buf, "%s/%s", RMTDEBUG, Rmtname);
847 		unlink(buf);
848 		if (link(temp, buf) != 0) {
849 			Debug = 0;
850 			assert("RMTDEBUG LINK FAIL", temp, errno);
851 			cleanup(1);
852 		}
853 		parm = DBG_CLEAN;
854 	}
855 	if (parm == DBG_CLEAN) {
856 		if (temp != CNULL) {
857 			unlink(temp);
858 			free(temp);
859 			temp = CNULL;
860 		}
861 		return;
862 	}
863 
864 	if (Debug == 0)
865 		return;		/* Gotta be in debug to come here.   */
866 
867 	/*
868 	 * If we haven't opened a file already, we can just return if it's
869 	 * alright to use the stderr we came in with. We can if:
870 	 *
871 	 *	Role == MASTER, and Stderr is a regular file, a TTY or a pipe.
872 	 *
873 	 * Caution: Detecting when stderr is a pipe is tricky, because the 4.2
874 	 * man page for fstat(2) disagrees with reality, and System V leaves it
875 	 * undefined, which means different implementations act differently.
876 	 */
877 	if (!auditopen && Role == MASTER) {
878 		if (isatty(fileno(stderr)))
879 			return;
880 		else if (fstat(fileno(stderr), &stbuf) == 0) {
881 #ifdef USG
882 			/* Is Regular File or Fifo   */
883 			if ((stbuf.st_mode & 0060000) == 0)
884 				return;
885 #else !USG
886 #ifdef BSD4_2
887 					/* Is Regular File */
888 			if ((stbuf.st_mode & S_IFMT) == S_IFREG ||
889 			    stbuf.st_mode == 0)		/* Is a pipe */
890 				return;
891 #else !BSD4_2
892 					 /* Is Regular File or Pipe  */
893 			if ((stbuf.st_mode & S_IFMT) == S_IFREG)
894 				return;
895 #endif BSD4_2
896 #endif USG
897 		}
898 	}
899 
900 	/*
901 	 * We need RMTDEBUG directory to do auditing. If the file doesn't exist,
902 	 * then we forget about debugging; if it exists but has improper owner-
903 	 * ship or modes, we gripe about it in ERRLOG.
904 	 */
905 	if (stat(RMTDEBUG, &stbuf) != SUCCESS) {
906 		Debug = 0;
907 		return;
908 	}
909 	if ((geteuid() != stbuf.st_uid) ||	  	/* We must own it    */
910 	    ((stbuf.st_mode & 0170700) != 040700)) {	/* Directory, rwx    */
911 		Debug = 0;
912 		assert("INVALID RMTDEBUG DIRECTORY:", RMTDEBUG, stbuf.st_mode);
913 		return;
914 	}
915 
916 	if (parm == DBG_TEMP) {
917 		sprintf(buf, "%s/%d", RMTDEBUG, getpid());
918 		temp = malloc(strlen (buf) + 1);
919 		if (temp == CNULL) {
920 			Debug = 0;
921 			assert("RMTDEBUG MALLOC ERROR:", temp, errno);
922 			cleanup(1);
923 		}
924 		strcpy(temp, buf);
925 	} else
926 		sprintf(buf, "%s/%s", RMTDEBUG, Rmtname);
927 
928 	unlink(buf);
929 	if (freopen(buf, "w", stderr) != stderr) {
930 		Debug = 0;
931 		assert("FAILED RMTDEBUG FILE OPEN:", buf, errno);
932 		cleanup(1);
933 	}
934 	setbuf(stderr, CNULL);
935 	auditopen = 1;
936 }
937 
938 /*
939  *	catch SIGALRM routine
940  */
941 timeout()
942 {
943 	extern int HaveSentHup;
944 	if (!HaveSentHup) {
945 		logent(Rmtname, "TIMEOUT");
946 		if (*Rmtname && strncmp(Rmtname, Myname, MAXBASENAME)) {
947 			US_SST(us_s_tmot);
948 			systat(Rmtname, SS_FAIL, "TIMEOUT");
949 		}
950 	}
951 	longjmp(Sjbuf, 1);
952 }
953 
954 static char *
955 pskip(p)
956 register char *p;
957 {
958 	while(*p && *p != ' ')
959 		++p;
960 	while(*p && *p == ' ')
961 		*p++ = 0;
962 	return p;
963 }
964