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