xref: /original-bsd/usr.bin/uucp/uucico/cico.c (revision 454fcdce)
1 #ifndef lint
2 static char sccsid[] = "@(#)cico.c	5.20	(Berkeley) 03/02/91";
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 	static void onintr(), timeout(), dbg_signal();
109 	static 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,
362 			    (struct sockaddr *)&from, &fromlen) < 0) {
363 				logent(Rmtname, "NOT A TCP CONNECTION");
364 				omsg('R', "NOT TCP", Ofn);
365 				cleanup(0);
366 			}
367 #endif	!NOGETPEER
368 			hp = gethostbyaddr((char *)&from.sin_addr,
369 				sizeof (struct in_addr), from.sin_family);
370 			if (hp == NULL) {
371 				/* security break or just old host table? */
372 				logent(Rmtname, "UNKNOWN IP-HOST Name =");
373 				cpnt = inet_ntoa(from.sin_addr),
374 				logent(cpnt, "UNKNOWN IP-HOST Number =");
375 				sprintf(wkpre, "%s/%s isn't in my host table",
376 					Rmtname, cpnt);
377 				omsg('R' ,wkpre ,Ofn);
378 				cleanup(0);
379 			}
380 			if (Debug > 99)
381 				logent(Rmtname,"Request from IP-Host name =");
382 			/*
383 			 * The following is to determine if the name given us by
384 			 * the Remote uucico matches any of the names
385 			 * given its network number (remote machine) in our
386 			 * host table.
387 			 * We could check the aliases, but that won't work in
388 			 * all cases (like if you are running the domain
389 			 * server, where you don't get any aliases). The only
390 			 * reliable way I can think of that works in ALL cases
391 			 * is too look up the site in L.sys and see if the
392 			 * sitename matches what we would call him if we
393 			 * originated the call.
394 			 */
395 			/* PhoneNumber contains the official network name of the 			   host we are checking. (set in versys.c) */
396 			if (sncncmp(PhoneNumber, hp->h_name, SYSNSIZE) == 0) {
397 				if (Debug > 99)
398 					logent(q,"Found in host Tables");
399 			} else {
400 				logent(hp->h_name, "FORGED HOSTNAME");
401 				logent(inet_ntoa(from.sin_addr), "ORIGINATED AT");
402 				logent(PhoneNumber, "SHOULD BE");
403 				sprintf(wkpre, "You're not who you claim to be: %s !=  %s", hp->h_name, PhoneNumber);
404 				omsg('R', wkpre, Ofn);
405 				cleanup(0);
406 			}
407 		}
408 #endif	BSDTCP
409 
410 		if (mlock(Rmtname)) {
411 			omsg('R', "LCK", Ofn);
412 			cleanup(0);
413 		}
414 		else if (callback(Loginuser)) {
415 			signal(SIGINT, SIG_IGN);
416 			signal(SIGHUP, SIG_IGN);
417 			omsg('R', "CB", Ofn);
418 			logent("CALLBACK", "REQUIRED");
419 			/*  set up for call back  */
420 			systat(Rmtname, SS_CALLBACK, "CALLING BACK");
421 			gename(CMDPRE, Rmtname, 'C', file);
422 			close(creat(subfile(file), 0666));
423 			xuucico(Rmtname);
424 			cleanup(0);
425 		}
426 		seq = 0;
427 		while (*p == '-') {
428 			q = pskip(p);
429 			switch(*(++p)) {
430 			case 'x':
431 				if (Debug == 0) {
432 					Debug = atoi(++p);
433 					if (Debug <= 0)
434 						Debug = 1;
435 					setdebug(DBG_PERM);
436 					if (Debug > 0)
437 						logent("Remote Enabled", "DEBUG");
438 				} else {
439 					DEBUG(1, "Remote debug request ignored\n",
440 					   CNULL);
441 				}
442 				break;
443 			case 'Q':
444 				seq = atoi(++p);
445 				break;
446 			case 'p':
447 				MaxGrade = DefMaxGrade = *++p;
448 				DEBUG(4, "MaxGrade set to %c\n", MaxGrade);
449 				break;
450 			case 'v':
451 				if (strncmp(p, "grade", 5) == 0) {
452 					p += 6;
453 					MaxGrade = DefMaxGrade = *p++;
454 					DEBUG(4, "MaxGrade set to %c\n", MaxGrade);
455 				}
456 				break;
457 			default:
458 				break;
459 			}
460 			p = q;
461 		}
462 		setproctitle("%s: startup", Rmtname);
463 		if (callok(Rmtname) == SS_BADSEQ) {
464 			logent("BADSEQ", "PREVIOUS");
465 			omsg('R', "BADSEQ", Ofn);
466 			cleanup(0);
467 		}
468 #ifdef GNXSEQ
469 		if ((ret = gnxseq(Rmtname)) == seq) {
470 			omsg('R', "OK", Ofn);
471 			cmtseq();
472 		} else {
473 #else !GNXSEQ
474 		if (seq == 0)
475 			omsg('R', "OK", Ofn);
476 		else {
477 #endif !GNXSEQ
478 			systat(Rmtname, Stattype[7], Stattext[7]);
479 			logent("BAD SEQ", "FAILED HANDSHAKE");
480 #ifdef GNXSEQ
481 			ulkseq();
482 #endif GNXSEQ
483 			omsg('R', "BADSEQ", Ofn);
484 			cleanup(0);
485 		}
486 		if (ttyn != NULL)
487 			chmod(ttyn, 0600);
488 	}
489 
490 loop:
491 	if(setjmp(Pipebuf)) {	/* come here on SIGPIPE	*/
492 		clsacu();
493 		logcls();
494 		close(Ofn);
495 		close(Ifn);
496 		Ifn = Ofn = -1;
497 		rmlock(CNULL);
498 		sleep(3);
499 	}
500 	if (!onesys) {
501 		do_connect_accounting();
502 #ifdef DIALINOUT
503 		/* reenable logins on dialout */
504 		reenable();
505 #endif DIALINOUT
506 		StartTime = 0;
507 		setproctitle("looking for work");
508 		ret = gnsys(Rmtname, Spool, CMDPRE);
509 		setproctitle("%s: startup", Rmtname);
510 		setdebug(DBG_PERM);
511 		if (ret == FAIL)
512 			cleanup(100);
513 		else if (ret == SUCCESS)
514 			cleanup(0);
515 		logcls();
516 	} else if (Role == MASTER && callok(Rmtname) != 0) {
517 		logent("SYSTEM STATUS", "CAN NOT CALL");
518 		cleanup(0);
519 	}
520 
521 	sprintf(wkpre, "%c.%.*s", CMDPRE, SYSNSIZE, Rmtname);
522 	StartTime = 0;
523 	Bytes_Sent = Bytes_Received = 0L;
524 
525 	signal(SIGINT, SIG_IGN);
526 	signal(SIGQUIT, SIG_IGN);
527 	if (Role == MASTER) {
528 		extern char LineType[];
529 		/* check for /etc/nologin */
530 		if (access(NOLOGIN, 0) == 0) {
531 			logent(NOLOGIN, "UUCICO SHUTDOWN");
532 			if (Debug > 4)
533 				logent("DEBUGGING", "continuing anyway");
534 			else
535 				cleanup(1);
536 		}
537 		/*  master part */
538 		signal(SIGHUP, SIG_IGN);
539 		if (Ifn != -1 && Role == MASTER) {
540 			write(Ofn, EOTMSG, strlen(EOTMSG));
541 			clsacu();
542 			close(Ofn);
543 			close(Ifn);
544 			Ifn = Ofn = -1;
545 			rmlock(CNULL);
546 			sleep(3);
547 		}
548 		if (mlock(Rmtname) != SUCCESS) {
549 			DEBUG(1, "LOCKED: call to %s\n", Rmtname);
550 			US_SST(us_s_lock);
551 			goto next;
552 		}
553 		setproctitle("%s: starting call", Rmtname);
554 		Ofn = Ifn = conn(Rmtname);
555 		sprintf(msg, "(call to %s via %s)", Rmtname, LineType);
556 		if (Ofn < 0) {
557 			if (Ofn != CF_TIME)
558 				logent(msg, _FAILED);
559 			/* avoid excessive 'wrong time' info */
560 			if (Stattype[-Ofn] != SS_WRONGTIME){
561 				systat(Rmtname, Stattype[-Ofn], Stattext[-Ofn]);
562 				US_SST(-Ofn);
563 				UB_SST(-Ofn);
564 			}
565 			goto next;
566 		} else {
567 			logent(msg, "SUCCEEDED");
568 			US_SST(us_s_cok);
569 			UB_SST(ub_ok);
570 		}
571 		InitialRole = MASTER;
572 #ifdef	TCPIP
573 		/*
574 		 * Determine if we are on TCPIP
575 		 */
576 		if (isatty(Ifn) == 0) {
577 			IsTcpIp = 1;
578 			DEBUG(4, "TCPIP connection -- ioctl-s disabled\n", CNULL);
579 		} else
580 			IsTcpIp = 0;
581 #endif
582 
583 		if (setjmp(Sjbuf))
584 			goto next;
585 		signal(SIGALRM, timeout);
586 		alarm(IsTcpIp?MAXMSGTIME*4:MAXMSGTIME*2);
587 		for (;;) {
588 			ret = imsg(msg, Ifn);
589 			if (ret != SUCCESS) {
590 				alarm(0);
591 				DEBUG(4,"\nimsg failed: errno %d\n", errno);
592 				logent("imsg 1", _FAILED);
593 				goto Failure;
594 			}
595 			if (msg[0] == 'S')
596 				break;
597 		}
598 		alarm(IsTcpIp?MAXMSGTIME*4:MAXMSGTIME);
599 #ifdef GNXSEQ
600 		seq = gnxseq(Rmtname);
601 #else !GNXSEQ
602 		seq = 0;
603 #endif !GNXSEQ
604 		if (MaxGrade != '\177') {
605 			DEBUG(2, "Max Grade this transfer is %c\n", MaxGrade);
606 			sprintf(msg, "%s -Q%d -p%c -vgrade=%c %s",
607 				Myname, seq, MaxGrade, MaxGrade, rflags);
608 		} else
609 			sprintf(msg, "%s -Q%d %s", Myname, seq, rflags);
610 		omsg('S', msg, Ofn);
611 		for (;;) {
612 			ret = imsg(msg, Ifn);
613 			DEBUG(4, "msg-%s\n", msg);
614 			if (ret != SUCCESS) {
615 				alarm(0);
616 #ifdef GNXSEQ
617 				ulkseq();
618 #endif GNXSEQ
619 				logent("imsg 2", _FAILED);
620 				goto Failure;
621 			}
622 			if (msg[0] == 'R')
623 				break;
624 		}
625 		alarm(0);
626 		if (msg[1] == 'B') {
627 			/* bad sequence */
628 			logent("BAD SEQ", "FAILED HANDSHAKE");
629 			US_SST(us_s_hand);
630 			systat(Rmtname, SS_BADSEQ, Stattext[SS_BADSEQ]);
631 #ifdef GNXSEQ
632 			ulkseq();
633 #endif GNXSEQ
634 			goto next;
635 		}
636 		if (strcmp(&msg[1], "OK") != SAME)  {
637 			logent(&msg[1], "FAILED HANDSHAKE");
638 			US_SST(us_s_hand);
639 #ifdef GNXSEQ
640 			ulkseq();
641 #endif GNXSEQ
642 			systat(Rmtname, SS_INPROGRESS,
643 				strcmp(&msg[1], "CB") == SAME?
644 				"AWAITING CALLBACK": "FAILED HANDSHAKE");
645 			goto next;
646 		}
647 #ifdef GNXSEQ
648 		cmtseq();
649 #endif GNXSEQ
650 	}
651 	DEBUG(1, "Rmtname %s, ", Rmtname);
652 	DEBUG(1, "Role %s,  ", Role ? "MASTER" : "SLAVE");
653 	DEBUG(1, "Ifn - %d, ", Ifn);
654 	DEBUG(1, "Loginuser - %s\n", Loginuser);
655 	setproctitle("%s: %s", Rmtname, Role ? "MASTER" : "SLAVE");
656 
657 	ttyn = ttyname(Ifn);
658 
659 	alarm(IsTcpIp?MAXMSGTIME*4:MAXMSGTIME);
660 	if (ret=setjmp(Sjbuf))
661 		goto Failure;
662 	ret = startup(Role);
663 	alarm(0);
664 	if (ret != SUCCESS) {
665 		logent("(startup)", _FAILED);
666 Failure:
667 		US_SST(us_s_start);
668 		systat(Rmtname, SS_FAIL, ret > 0 ? "CONVERSATION FAILED" :
669 			"STARTUP FAILED");
670 		goto next;
671 	} else {
672 		char smsg[BUFSIZ], gmsg[10], pmsg[20], bpsmsg[20];
673 		extern char UsingProtocol;
674 		extern int linebaudrate;
675 		if (ttyn != NULL)
676 			sprintf(bpsmsg, " %s %d bps", &ttyn[5], linebaudrate);
677 		else
678 			bpsmsg[0] = '\0';
679 		if (UsingProtocol != 'g')
680 			sprintf(pmsg, " %c protocol", UsingProtocol);
681 		else
682 			pmsg[0] = '\0';
683 		if (MaxGrade != '\177')
684 			sprintf(gmsg, " grade %c", MaxGrade);
685 		else
686 			gmsg[0] = '\0';
687 		sprintf(smsg, "(startup%s%s%s)", bpsmsg, pmsg, gmsg);
688 		logent(smsg, "OK");
689 		US_SST(us_s_gress);
690 		StartTime = Now.time;
691 		systat(Rmtname, SS_INPROGRESS, "TALKING");
692 		ret = cntrl(Role, wkpre);
693 		DEBUG(1, "cntrl - %d\n", ret);
694 		signal(SIGINT, SIG_IGN);
695 		signal(SIGHUP, SIG_IGN);
696 		signal(SIGALRM, timeout);
697 		sprintf(smsg, "(conversation complete %ld sent %ld received)",
698 			Bytes_Sent, Bytes_Received);
699 		if (ret == SUCCESS) {
700 			logent(smsg, "OK");
701 			US_SST(us_s_ok);
702 			rmstat(Rmtname);
703 
704 		} else {
705 			logent(smsg, _FAILED);
706 			US_SST(us_s_cf);
707 			systat(Rmtname, SS_FAIL, "CONVERSATION FAILED");
708 		}
709 		alarm(IsTcpIp?MAXMSGTIME*4:MAXMSGTIME);
710 		DEBUG(4, "send OO %d,", ret);
711 		if (!setjmp(Sjbuf)) {
712 			for (;;) {
713 				omsg('O', "OOOOO", Ofn);
714 				ret = imsg(msg, Ifn);
715 				if (ret != 0)
716 					break;
717 				if (msg[0] == 'O')
718 					break;
719 			}
720 		}
721 		alarm(0);
722 		clsacu();
723 		rmlock(CNULL);
724 
725 	}
726 next:
727 	if (!onesys) {
728 		goto loop;
729 	}
730 	cleanup(0);
731 }
732 
733 #ifndef	USG
734 struct sgttyb Hupvec;
735 #endif
736 
737 /*
738  *	cleanup and exit with "code" status
739  */
740 cleanup(code)
741 register int code;
742 {
743 	signal(SIGINT, SIG_IGN);
744 	signal(SIGHUP, SIG_IGN);
745 	rmlock(CNULL);
746 	sleep(5);			/* Wait for any pending output	  */
747 	clsacu();
748 	logcls();
749 	if (Role == SLAVE) {
750 		if (!IsTcpIp) {
751 #ifdef USG
752 			Savettyb.c_cflag |= HUPCL;
753 			(void) ioctl(0, TCSETA, &Savettyb);
754 #else !USG
755 			(void) ioctl(0, TIOCHPCL, STBNULL);
756 #ifdef TIOCSDTR
757 			(void) ioctl(0, TIOCCDTR, STBNULL);
758 			sleep(2);
759 			(void) ioctl(0, TIOCSDTR, STBNULL);
760 #else !TIOCSDTR
761 			(void) ioctl(0, TIOCGETP, &Hupvec);
762 			Hupvec.sg_ispeed = B0;
763 			Hupvec.sg_ospeed = B0;
764 			(void) ioctl(0, TIOCSETP, &Hupvec);
765 #endif !TIOCSDTR
766 			sleep(2);
767 			(void) ioctl(0, TIOCSETP, &Savettyb);
768 			/* make *sure* exclusive access is off */
769 			(void) ioctl(0, TIOCNXCL, STBNULL);
770 #endif !USG
771 		}
772 		if (ttyn != NULL)
773 			chmod(ttyn, 0600);
774 	}
775 	if (Ofn != -1) {
776 		if (Role == MASTER)
777 			write(Ofn, EOTMSG, strlen(EOTMSG));
778 		close(Ifn);
779 		close(Ofn);
780 	}
781 #ifdef DIALINOUT
782 	/* reenable logins on dialout */
783 	reenable();
784 #endif DIALINOUT
785 	if (code == 0)
786 		xuuxqt();
787 	else
788 		DEBUG(1, "exit code %d\n", code);
789 	setdebug (DBG_CLEAN);
790 	do_connect_accounting();
791 	exit(code);
792 }
793 
794 do_connect_accounting()
795 {
796 #ifdef DO_CONNECT_ACCOUNTING
797 	register FILE *fp;
798 	struct tm *localtime();
799 	register struct tm *tm;
800 	int flags;
801 
802 	if (StartTime == 0)
803 		return;
804 
805 	fp = fopen(DO_CONNECT_ACCOUNTING, "a");
806 	if (fp == NULL) {
807 		syslog(LOG_ALERT, "fopen(%s) failed: %m",DO_CONNECT_ACCOUNTING);
808 		cleanup(FAIL);
809 	}
810 
811 	tm = localtime(&StartTime);
812 #ifdef F_SETFL
813 	flags = fcntl(fileno(fp), F_GETFL, 0);
814 	fcntl(fileno(fp), F_SETFL, flags|O_APPEND);
815 #endif
816 #ifdef USG
817 	fprintf(fp,"%s %d %d%.2d%.2d %.2d%.2d %d %ld %s %ld %ld\n",
818 #else /* V7 */
819 	fprintf(fp,"%s %d %d%02d%02d %02d%02d %d %ld %s %ld %ld\n",
820 #endif /* V7 */
821 		Rmtname, InitialRole, tm->tm_year, tm->tm_mon + 1,
822 		tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_wday,
823 		(Now.time - StartTime + 59) / 60,
824 		ttyn == NULL ? "ttyp0" : &ttyn[5],
825 			Bytes_Sent, Bytes_Received);
826 	fclose(fp);
827 #endif /* DO_CONNECT_ACCOUNTING */
828 }
829 
830 /*
831  *	on interrupt - remove locks and exit
832  */
833 
834 static void
835 onintr(inter)
836 register int inter;
837 {
838 	char str[BUFSIZ];
839 	signal(inter, SIG_IGN);
840 	sprintf(str, "(SIGNAL %d)", inter);
841 	logent(str, "CAUGHT");
842 	US_SST(us_s_intr);
843 	if (*Rmtname && strncmp(Rmtname, Myname, MAXBASENAME))
844 		systat(Rmtname, SS_FAIL, str);
845 	sprintf(str, "(conversation complete %ld sent %ld received)",
846 		Bytes_Sent, Bytes_Received);
847 	logent(str, _FAILED);
848 	if (inter == SIGPIPE && !onesys)
849 		longjmp(Pipebuf, 1);
850 	cleanup(inter);
851 }
852 
853 /*
854  * Catch a special signal
855  * (SIGUSR1), and toggle debugging between 0 and 30.
856  * Handy for looking in on long running uucicos.
857  */
858 static void
859 dbg_signal()
860 {
861 	Debug = (Debug == 0) ? 30 : 0;
862 	setdebug(DBG_PERM);
863 	if (Debug > 0)
864 		logent("Signal Enabled", "DEBUG");
865 }
866 
867 
868 /*
869  * Check debugging requests, and open RMTDEBUG audit file if necessary. If an
870  * audit file is needed, the parm argument indicates how to create the file:
871  *
872  *	DBG_TEMP  - Open a temporary file, with filename = RMTDEBUG/pid.
873  *	DBG_PERM  - Open a permanent audit file, filename = RMTDEBUG/Rmtname.
874  *		    If a temp file already exists, it is mv'ed to be permanent.
875  *	DBG_CLEAN - Cleanup; unlink temp files.
876  *
877  * Restrictions - this code can only cope with one open debug file at a time.
878  * Each call creates a new file; if an old one of the same name exists it will
879  * be overwritten.
880  */
881 setdebug(parm)
882 int parm;
883 {
884 	char buf[BUFSIZ];		/* Buffer for building filenames     */
885 	static char *temp = NULL;	/* Ptr to temporary file name	     */
886 	static int auditopen = 0;	/* Set to 1 when we open a file	     */
887 	struct stat stbuf;		/* File status buffer		     */
888 
889 	/*
890 	 * If movement or cleanup of a temp file is indicated, we do it no
891 	 * matter what.
892 	 */
893 	if (temp != CNULL && parm == DBG_PERM) {
894 		sprintf(buf, "%s/%s", RMTDEBUG, Rmtname);
895 		unlink(buf);
896 		if (link(temp, buf) != 0) {
897 			Debug = 0;
898 			syslog(LOG_ERR, "RMTDEBUG link(%s,%s) failed: %m",
899 				temp, buf);
900 			cleanup(FAIL);
901 		}
902 		parm = DBG_CLEAN;
903 	}
904 	if (parm == DBG_CLEAN) {
905 		if (temp != CNULL) {
906 			unlink(temp);
907 			free(temp);
908 			temp = CNULL;
909 		}
910 		return;
911 	}
912 
913 	if (Debug == 0)
914 		return;		/* Gotta be in debug to come here.   */
915 
916 	/*
917 	 * If we haven't opened a file already, we can just return if it's
918 	 * alright to use the stderr we came in with. We can if:
919 	 *
920 	 *	Role == MASTER, and Stderr is a regular file, a TTY or a pipe.
921 	 *
922 	 * Caution: Detecting when stderr is a pipe is tricky, because the 4.2
923 	 * man page for fstat(2) disagrees with reality, and System V leaves it
924 	 * undefined, which means different implementations act differently.
925 	 */
926 	if (!auditopen && Role == MASTER) {
927 		if (isatty(fileno(stderr)))
928 			return;
929 		else if (fstat(fileno(stderr), &stbuf) == 0) {
930 #ifdef USG
931 			/* Is Regular File or Fifo   */
932 			if ((stbuf.st_mode & 0060000) == 0)
933 				return;
934 #else !USG
935 #ifdef BSD4_2
936 					/* Is Regular File */
937 			if ((stbuf.st_mode & S_IFMT) == S_IFREG ||
938 			    stbuf.st_mode == 0)		/* Is a pipe */
939 				return;
940 #else !BSD4_2
941 					 /* Is Regular File or Pipe  */
942 			if ((stbuf.st_mode & S_IFMT) == S_IFREG)
943 				return;
944 #endif BSD4_2
945 #endif USG
946 		}
947 	}
948 
949 	/*
950 	 * We need RMTDEBUG directory to do auditing. If the file doesn't exist,
951 	 * then we forget about debugging; if it exists but has improper owner-
952 	 * ship or modes, we gripe about it in ERRLOG.
953 	 */
954 	if (stat(RMTDEBUG, &stbuf) != SUCCESS) {
955 		Debug = 0;
956 		return;
957 	}
958 	if ((geteuid() != stbuf.st_uid) ||	  	/* We must own it    */
959 	    ((stbuf.st_mode & 0170700) != 040700)) {	/* Directory, rwx    */
960 		Debug = 0;
961 		syslog(LOG_ERR, "%s: invalid directory mode: %o", RMTDEBUG,
962 			stbuf.st_mode);
963 		return;
964 	}
965 
966 	if (parm == DBG_TEMP) {
967 		sprintf(buf, "%s/%d", RMTDEBUG, getpid());
968 		temp = malloc(strlen (buf) + 1);
969 		if (temp == CNULL) {
970 			Debug = 0;
971 			syslog(LOG_ERR, "RMTDEBUG malloc failed: %m");
972 			cleanup(FAIL);
973 		}
974 		strcpy(temp, buf);
975 	} else
976 		sprintf(buf, "%s/%s", RMTDEBUG, Rmtname);
977 
978 	unlink(buf);
979 	if (freopen(buf, "w", stderr) != stderr) {
980 		Debug = 0;
981 		syslog(LOG_ERR, "RMTDEBUG freopen(%s) failed: %m", buf);
982 		cleanup(FAIL);
983 	}
984 	setbuf(stderr, CNULL);
985 	auditopen = 1;
986 }
987 
988 /*
989  *	catch SIGALRM routine
990  */
991 static void
992 timeout()
993 {
994 	extern int HaveSentHup;
995 	if (!HaveSentHup) {
996 		logent(Rmtname, "TIMEOUT");
997 		if (*Rmtname && strncmp(Rmtname, Myname, MAXBASENAME)) {
998 			US_SST(us_s_tmot);
999 			systat(Rmtname, SS_FAIL, "TIMEOUT");
1000 		}
1001 	}
1002 	longjmp(Sjbuf, 1);
1003 }
1004 
1005 static char *
1006 pskip(p)
1007 register char *p;
1008 {
1009 	while(*p && *p != ' ')
1010 		++p;
1011 	while(*p && *p == ' ')
1012 		*p++ = 0;
1013 	return p;
1014 }
1015 
1016 /*
1017  * clobber argv so ps will show what we're doing.
1018  * stolen from sendmail
1019  */
1020 /*VARARGS1*/
1021 setproctitle(fmt, a, b, c)
1022 char *fmt;
1023 {
1024 #ifdef SETPROCTITLE
1025 	register char *p;
1026 	register int i;
1027 	extern char **Argv;
1028 	extern char *LastArgv;
1029 	char buf[BUFSIZ];
1030 
1031 	(void) sprintf(buf, fmt, a, b, c);
1032 
1033 	/* make ps print "(sendmail)" */
1034 	p = Argv[0];
1035 	*p++ = '-';
1036 
1037 	i = strlen(buf);
1038 	if (i > LastArgv - p - 2) {
1039 		i = LastArgv - p - 2;
1040 		buf[i] = '\0';
1041 	}
1042 	(void) strcpy(p, buf);
1043 	p += i;
1044 	while (p < LastArgv)
1045 		*p++ = ' ';
1046 #endif SETPROCTITLE
1047 }
1048