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