1 /*- 2 * Copyright (c) 1985 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * %sccs.include.proprietary.c% 6 */ 7 8 #ifndef lint 9 static char sccsid[] = "@(#)cico.c 5.21 (Berkeley) 04/24/91"; 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 */ 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 */ 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 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 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 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 */ 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 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 * 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*/ 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