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