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