113639Ssam #ifndef lint 2*36449Smarc static char sccsid[] = "@(#)cico.c 5.18 (Berkeley) 12/20/88"; 313639Ssam #endif 413639Ssam 523590Sbloom #include <signal.h> 613639Ssam #include "uucp.h" 713639Ssam #include <setjmp.h> 817767Sralph #ifdef USG 913639Ssam #include <termio.h> 1033559Srick #include <fcntl.h> 1113639Ssam #endif 1217767Sralph #ifndef USG 1313639Ssam #include <sgtty.h> 1413639Ssam #endif 1517767Sralph #ifdef BSDTCP 1617767Sralph #include <netdb.h> 1717767Sralph #include <netinet/in.h> 1817767Sralph #include <sys/socket.h> 1917767Sralph #endif BSDTCP 2017767Sralph #include <sys/stat.h> 2133559Srick #ifdef BSD4_2 2233559Srick #include <sys/time.h> 2333559Srick #include <fcntl.h> 2433559Srick #else 2533559Srick #include <time.h> 2633559Srick #endif 2717767Sralph #include "uust.h" 2817767Sralph #include "uusub.h" 2913639Ssam 3023590Sbloom #if defined(VMS) && defined(BSDTCP) 3123590Sbloom #define NOGETPEER 3223590Sbloom #endif 3323590Sbloom 3417767Sralph jmp_buf Sjbuf; 3517767Sralph jmp_buf Pipebuf; 3613639Ssam 3717767Sralph /* call fail text */ 3813639Ssam char *Stattext[] = { 3913639Ssam "", 4013639Ssam "BAD SYSTEM", 4117767Sralph "WRONG TIME TO CALL", 4213639Ssam "SYSTEM LOCKED", 4313639Ssam "NO DEVICE", 4425703Sbloom "CALL FAILED", 4513639Ssam "LOGIN FAILED", 4613639Ssam "BAD SEQUENCE" 4717767Sralph }; 4813639Ssam 4917767Sralph /* call fail codes */ 5017767Sralph int Stattype[] = { 5117767Sralph 0, 5217767Sralph 0, 5317767Sralph SS_WRONGTIME, 5417767Sralph 0, 5517767Sralph SS_NODEVICE, 5617767Sralph SS_FAIL, 5717767Sralph SS_FAIL, 5817767Sralph SS_BADSEQ 5917767Sralph }; 6013639Ssam 6125703Sbloom /* Arguments to setdebug(): */ 6225703Sbloom #define DBG_TEMP 0 /* Create a temporary audit file */ 6325703Sbloom #define DBG_PERM 1 /* Create a permanent audit file */ 6425703Sbloom #define DBG_CLEAN 2 /* Cleanup, discard temp file */ 6513639Ssam 6617767Sralph int ReverseRole = 0; 6717767Sralph int Role = SLAVE; 6833559Srick int InitialRole = SLAVE; 6933559Srick long StartTime; 7017767Sralph int onesys = 0; 7118616Sralph int turntime = 30 * 60; /* 30 minutes expressed in seconds */ 7225703Sbloom char *ttyn = NULL; 7317767Sralph extern int LocalOnly; 7425703Sbloom extern int errno; 7518616Sralph extern char MaxGrade, DefMaxGrade; 7618616Sralph extern char Myfullname[]; 7717767Sralph 7833559Srick long Bytes_Sent, Bytes_Received; 7933559Srick 8017767Sralph #ifdef USG 8113639Ssam struct termio Savettyb; 8213639Ssam #endif 8317767Sralph #ifndef USG 8413639Ssam struct sgttyb Savettyb; 8513639Ssam #endif 8613639Ssam 8734164Srick #define SETPROCTITLE 8834164Srick #ifdef SETPROCTITLE 8934164Srick char **Argv = NULL; /* pointer to argument vector */ 9034164Srick char *LastArgv = NULL; /* end of argv */ 9134164Srick #endif SETPROCTITLE 9234164Srick 9325703Sbloom /* 9425703Sbloom * this program is used to place a call to a 9513639Ssam * remote machine, login, and copy files between the two machines. 9613639Ssam */ 9734164Srick main(argc, argv, envp) 9825703Sbloom int argc; 9933945Srick char **argv; 10034164Srick char **envp; 10113639Ssam { 10213639Ssam register int ret; 10313639Ssam int seq; 10413639Ssam char wkpre[NAMESIZE], file[NAMESIZE]; 10525703Sbloom char msg[MAXFULLNAME], *q; 10613639Ssam register char *p; 10725703Sbloom extern onintr(), timeout(), dbg_signal(); 10813639Ssam extern char *pskip(); 10933945Srick extern char *optarg; 11033945Srick extern int optind; 11123725Sbloom char rflags[MAXFULLNAME]; 11223590Sbloom #ifdef NOGETPEER 11317767Sralph u_long Hostnumber = 0; 11423590Sbloom #endif NOGETPEER 11513639Ssam 11613639Ssam strcpy(Progname, "uucico"); 11713639Ssam 11826149Sbloom #ifdef BSD4_2 11933945Srick sigsetmask(0L); /* in case we inherit blocked signals */ 12026149Sbloom #endif BSD4_2 12113639Ssam signal(SIGINT, onintr); 12213639Ssam signal(SIGHUP, onintr); 12313639Ssam signal(SIGQUIT, onintr); 12413639Ssam signal(SIGTERM, onintr); 12513639Ssam signal(SIGPIPE, onintr); /* 4.1a tcp-ip stupidity */ 126*36449Smarc signal(SIGUSR1, dbg_signal); 12713639Ssam ret = guinfo(getuid(), User, msg); 12813639Ssam strcpy(Loginuser, User); 12923590Sbloom uucpname(Myname); 13033945Srick if (ret == FAIL) { 13133945Srick syslog(LOG_ERR, "can't get uid"); 13233945Srick cleanup(FAIL); 13333945Srick } 13413639Ssam 13525703Sbloom setbuf (stderr, CNULL); 13625703Sbloom 13725703Sbloom rflags[0] = '\0'; 13813639Ssam umask(WFMASK); 13913639Ssam strcpy(Rmtname, Myname); 14013639Ssam Ifn = Ofn = -1; 14133945Srick while ((ret = getopt(argc, argv, "RLd:g:p:r:s:x:t:")) != EOF) 14233945Srick switch(ret){ 14313639Ssam case 'd': 14433945Srick Spool = optarg; 14513639Ssam break; 14613639Ssam case 'g': 14718616Sralph case 'p': 14833945Srick MaxGrade = DefMaxGrade = *optarg; 14913639Ssam break; 15013639Ssam case 'r': 15133945Srick Role = atoi(optarg); 15213639Ssam break; 15317767Sralph case 'R': 15417767Sralph ReverseRole++; 15517767Sralph Role = MASTER; 15617767Sralph break; 15713639Ssam case 's': 15833945Srick strncpy(Rmtname, optarg, MAXBASENAME); 15923590Sbloom Rmtname[MAXBASENAME] = '\0'; 16013639Ssam if (Rmtname[0] != '\0') 16113639Ssam onesys = 1; 16213639Ssam break; 16313639Ssam case 'x': 16433945Srick Debug = atoi(optarg); 16513639Ssam if (Debug <= 0) 16613639Ssam Debug = 1; 16733945Srick strcat(rflags, argv[optind-1]); 16813639Ssam break; 16918616Sralph case 't': 17033945Srick turntime = atoi(optarg)*60;/* minutes to seconds */ 17118616Sralph break; 17217767Sralph case 'L': /* local calls only */ 17317767Sralph LocalOnly++; 17417767Sralph break; 17523590Sbloom #ifdef NOGETPEER 17617767Sralph case 'h': 17717767Sralph Hostnumber = inet_addr(&argv[1][2]); 17817767Sralph break; 17923590Sbloom #endif NOGETPEER 18033945Srick case '?': 18113639Ssam default: 18233945Srick fprintf(stderr, "unknown flag %s (ignored)\n", 18333945Srick argv[optind-1]); 18413639Ssam break; 18513639Ssam } 18613639Ssam 18733945Srick while (optind < argc) 18833945Srick fprintf(stderr, "unknown argument %s (ignored)\n", 18933945Srick argv[optind++]); 19017767Sralph 19127069Sbloom if (Debug && Role == MASTER) 19227069Sbloom chkdebug(); 19327069Sbloom 19434164Srick #ifdef SETPROCTITLE 19534164Srick /* 19634164Srick * Save start and extent of argv for setproctitle. 19734164Srick */ 19834164Srick 19934164Srick Argv = argv; 20034164Srick LastArgv = argv[argc - 1] + strlen(argv[argc - 1]); 20134164Srick #endif SETPROCTITLE 20234164Srick 20325124Sbloom /* Try to run as uucp */ 20417767Sralph setgid(getegid()); 20517767Sralph setuid(geteuid()); 20617767Sralph #ifdef TIOCNOTTY 20717767Sralph /* 20817767Sralph * detach uucico from controlling terminal 20917767Sralph * to defend against rlogind sending us a SIGKILL (!!!) 21017767Sralph */ 21117767Sralph if (Role == MASTER && (ret = open("/dev/tty", 2)) >= 0) { 21217767Sralph ioctl(ret, TIOCNOTTY, STBNULL); 21317767Sralph close(ret); 21417767Sralph } 21517767Sralph #endif TIOCNOTTY 21617767Sralph #ifdef BSD4_2 21725517Stef if (getpgrp(0) == 0) { /* We have no controlling terminal */ 21817767Sralph setpgrp(0, getpid()); 21917767Sralph } 22033945Srick #ifdef USE_SYSLOG 22133945Srick #ifdef BSD4_3 22233945Srick openlog("uucico", LOG_PID, LOG_UUCP); 22333945Srick #else /* !BSD4_3 */ 22433945Srick openlog("uucico", LOG_PID); 22533945Srick #endif /* !BSD4_3 */ 22633945Srick #endif /* USE_SYSLOG */ 22717767Sralph #endif BSD4_2 22817767Sralph 22933945Srick #ifdef BSD4_3 23033945Srick unsetenv("TZ"); /* We don't want him resetting our time zone */ 23133945Srick #endif /* !BSD4_3 */ 23233945Srick 23333945Srick if (subchdir(Spool) < 0) { 23433945Srick syslog(LOG_ERR, "chdir(%s) failed: %m", Spool); 23533945Srick cleanup(FAIL); 23633945Srick } 23733945Srick 23813639Ssam strcpy(Wrkdir, Spool); 23913639Ssam 24025703Sbloom if (Debug) { 24125703Sbloom setdebug ((Role == SLAVE) ? DBG_TEMP : DBG_PERM); 24225703Sbloom if (Debug > 0) 24325703Sbloom logent ("Local Enabled", "DEBUG"); 24425703Sbloom } 24525703Sbloom 24625703Sbloom /* 24725703Sbloom * First time through: If we're the slave, do initial checking. 24825703Sbloom */ 24913639Ssam if (Role == SLAVE) { 25017767Sralph /* check for /etc/nologin */ 25125124Sbloom if (access(NOLOGIN, 0) == 0) { 25217767Sralph logent(NOLOGIN, "UUCICO SHUTDOWN"); 25323590Sbloom if (Debug > 4) 25417767Sralph logent("DEBUGGING", "continuing anyway"); 25517767Sralph else 25617767Sralph cleanup(1); 25717767Sralph } 25825703Sbloom Ifn = 0; 25925703Sbloom Ofn = 1; 26017767Sralph #ifdef TCPIP 26117767Sralph /* 26217767Sralph * Determine if we are on TCPIP 26317767Sralph */ 26433559Srick if (isatty(Ifn) == 0) { 26517767Sralph IsTcpIp = 1; 26617767Sralph DEBUG(4, "TCPIP connection -- ioctl-s disabled\n", CNULL); 26723590Sbloom } else 26823590Sbloom IsTcpIp = 0; 26917767Sralph #endif TCPIP 27013639Ssam /* initial handshake */ 27113639Ssam onesys = 1; 27217767Sralph if (!IsTcpIp) { 27317767Sralph #ifdef USG 27425703Sbloom ret = ioctl(Ifn, TCGETA, &Savettyb); 27513639Ssam Savettyb.c_cflag = (Savettyb.c_cflag & ~CS8) | CS7; 27613639Ssam Savettyb.c_oflag |= OPOST; 27713639Ssam Savettyb.c_lflag |= (ISIG|ICANON|ECHO); 27817767Sralph #else !USG 27925703Sbloom ret = ioctl(Ifn, TIOCGETP, &Savettyb); 28013639Ssam Savettyb.sg_flags |= ECHO; 28113639Ssam Savettyb.sg_flags &= ~RAW; 28217767Sralph #endif !USG 28325703Sbloom ttyn = ttyname(Ifn); 28413639Ssam } 28513639Ssam fixmode(Ifn); 28625703Sbloom 28725703Sbloom /* 28825703Sbloom * Initial Message -- tell them we're here, and who we are. 28925703Sbloom */ 29018616Sralph sprintf(msg, "here=%s", Myfullname); 29117767Sralph omsg('S', msg, Ofn); 29213639Ssam signal(SIGALRM, timeout); 29333559Srick alarm(IsTcpIp?MAXMSGTIME*4:MAXMSGTIME); 29413639Ssam if (setjmp(Sjbuf)) { 29513639Ssam /* timed out */ 29617767Sralph if (!IsTcpIp) { 29717767Sralph #ifdef USG 29825703Sbloom ret = ioctl(Ifn, TCSETA, &Savettyb); 29925703Sbloom 30023590Sbloom #else !USG 30125703Sbloom ret = ioctl(Ifn, TIOCSETP, &Savettyb); 30223590Sbloom #endif !USG 30313639Ssam } 30417767Sralph cleanup(0); 30513639Ssam } 30613639Ssam for (;;) { 30713639Ssam ret = imsg(msg, Ifn); 30825703Sbloom if (ret != SUCCESS) { 30913639Ssam alarm(0); 31017767Sralph if (!IsTcpIp) { 31117767Sralph #ifdef USG 31225703Sbloom ret = ioctl(Ifn, TCSETA, &Savettyb); 31323590Sbloom #else !USG 31425703Sbloom ret = ioctl(Ifn, TIOCSETP, &Savettyb); 31523590Sbloom #endif !USG 31613639Ssam } 31717767Sralph cleanup(0); 31813639Ssam } 31913639Ssam if (msg[0] == 'S') 32013639Ssam break; 32113639Ssam } 32213639Ssam alarm(0); 32313639Ssam q = &msg[1]; 32413639Ssam p = pskip(q); 32523590Sbloom strncpy(Rmtname, q, MAXBASENAME); 32623590Sbloom Rmtname[MAXBASENAME] = '\0'; 32725703Sbloom 32825703Sbloom /* 32925703Sbloom * Now that we know who they are, give the audit file the right 33025703Sbloom * name. 33125703Sbloom */ 33225703Sbloom setdebug (DBG_PERM); 33313639Ssam DEBUG(4, "sys-%s\n", Rmtname); 33423725Sbloom /* The versys will also do an alias on the incoming name */ 33523725Sbloom if (versys(&Rmtname)) { 33633559Srick #ifdef NOSTRANGERS 33723725Sbloom /* If we don't know them, we won't talk to them... */ 33833945Srick syslog(LOG_WARNING, "Unknown host: %s", Rmtname); 33923590Sbloom omsg('R', "You are unknown to me", Ofn); 34023590Sbloom cleanup(0); 34123725Sbloom #endif NOSTRANGERS 34223590Sbloom } 34317767Sralph #ifdef BSDTCP 34417767Sralph /* we must make sure they are really who they say they 34517767Sralph * are. We compare the hostnumber with the number in the hosts 34617767Sralph * table for the site they claim to be. 34717767Sralph */ 34817767Sralph if (IsTcpIp) { 34917767Sralph struct hostent *hp; 35017767Sralph char *cpnt, *inet_ntoa(); 35125703Sbloom int fromlen; 35217767Sralph struct sockaddr_in from; 35325124Sbloom extern char PhoneNumber[]; 35417767Sralph 35523590Sbloom #ifdef NOGETPEER 35623590Sbloom from.sin_addr.s_addr = Hostnumber; 35723590Sbloom from.sin_family = AF_INET; 35823590Sbloom #else !NOGETPEER 35925703Sbloom fromlen = sizeof(from); 36025703Sbloom if (getpeername(Ifn, &from, &fromlen) < 0) { 36117767Sralph logent(Rmtname, "NOT A TCP CONNECTION"); 36217767Sralph omsg('R', "NOT TCP", Ofn); 36317767Sralph cleanup(0); 36417767Sralph } 36523590Sbloom #endif !NOGETPEER 36617767Sralph hp = gethostbyaddr(&from.sin_addr, 36717767Sralph sizeof (struct in_addr), from.sin_family); 36825703Sbloom if (hp == NULL) { 36917767Sralph /* security break or just old host table? */ 37017767Sralph logent(Rmtname, "UNKNOWN IP-HOST Name ="); 37117767Sralph cpnt = inet_ntoa(from.sin_addr), 37217767Sralph logent(cpnt, "UNKNOWN IP-HOST Number ="); 37317767Sralph sprintf(wkpre, "%s/%s isn't in my host table", 37417767Sralph Rmtname, cpnt); 37517767Sralph omsg('R' ,wkpre ,Ofn); 37617767Sralph cleanup(0); 37717767Sralph } 37825703Sbloom if (Debug > 99) 37917767Sralph logent(Rmtname,"Request from IP-Host name ="); 38025124Sbloom /* 38125124Sbloom * The following is to determine if the name given us by 38225124Sbloom * the Remote uucico matches any of the names 38317767Sralph * given its network number (remote machine) in our 38417767Sralph * host table. 38525124Sbloom * We could check the aliases, but that won't work in 38625124Sbloom * all cases (like if you are running the domain 38725124Sbloom * server, where you don't get any aliases). The only 38825124Sbloom * reliable way I can think of that works in ALL cases 38925124Sbloom * is too look up the site in L.sys and see if the 39025124Sbloom * sitename matches what we would call him if we 39125124Sbloom * originated the call. 39217767Sralph */ 39325124Sbloom /* PhoneNumber contains the official network name of the host we are checking. (set in versys.c) */ 39425124Sbloom if (sncncmp(PhoneNumber, hp->h_name, SYSNSIZE) == 0) { 39517767Sralph if (Debug > 99) 39617767Sralph logent(q,"Found in host Tables"); 39725124Sbloom } else { 39825124Sbloom logent(hp->h_name, "FORGED HOSTNAME"); 39925124Sbloom logent(inet_ntoa(from.sin_addr), "ORIGINATED AT"); 40025124Sbloom logent(PhoneNumber, "SHOULD BE"); 40125124Sbloom sprintf(wkpre, "You're not who you claim to be: %s != %s", hp->h_name, PhoneNumber); 40225124Sbloom omsg('R', wkpre, Ofn); 40325124Sbloom cleanup(0); 40417767Sralph } 40517767Sralph } 40617767Sralph #endif BSDTCP 40717767Sralph 40825703Sbloom if (mlock(Rmtname)) { 40913639Ssam omsg('R', "LCK", Ofn); 41013639Ssam cleanup(0); 41113639Ssam } 41213639Ssam else if (callback(Loginuser)) { 41313639Ssam signal(SIGINT, SIG_IGN); 41413639Ssam signal(SIGHUP, SIG_IGN); 41513639Ssam omsg('R', "CB", Ofn); 41613639Ssam logent("CALLBACK", "REQUIRED"); 41713639Ssam /* set up for call back */ 41817767Sralph systat(Rmtname, SS_CALLBACK, "CALLING BACK"); 41913639Ssam gename(CMDPRE, Rmtname, 'C', file); 42013639Ssam close(creat(subfile(file), 0666)); 42113639Ssam xuucico(Rmtname); 42213639Ssam cleanup(0); 42313639Ssam } 42413639Ssam seq = 0; 42513639Ssam while (*p == '-') { 42613639Ssam q = pskip(p); 42713639Ssam switch(*(++p)) { 42813639Ssam case 'x': 42925703Sbloom if (Debug == 0) { 43025703Sbloom Debug = atoi(++p); 43125703Sbloom if (Debug <= 0) 43225703Sbloom Debug = 1; 43325703Sbloom setdebug(DBG_PERM); 43425703Sbloom if (Debug > 0) 43525703Sbloom logent("Remote Enabled", "DEBUG"); 43625703Sbloom } else { 43725703Sbloom DEBUG(1, "Remote debug request ignored\n", 43825703Sbloom CNULL); 43925703Sbloom } 44013639Ssam break; 44113639Ssam case 'Q': 44213639Ssam seq = atoi(++p); 44313639Ssam break; 44418616Sralph case 'p': 44518616Sralph MaxGrade = DefMaxGrade = *++p; 44618616Sralph DEBUG(4, "MaxGrade set to %c\n", MaxGrade); 44718616Sralph break; 44823590Sbloom case 'v': 44923590Sbloom if (strncmp(p, "grade", 5) == 0) { 45023590Sbloom p += 6; 45123590Sbloom MaxGrade = DefMaxGrade = *p++; 45223590Sbloom DEBUG(4, "MaxGrade set to %c\n", MaxGrade); 45323590Sbloom } 45423590Sbloom break; 45513639Ssam default: 45613639Ssam break; 45713639Ssam } 45813639Ssam p = q; 45913639Ssam } 46034164Srick setproctitle("%s: startup", Rmtname); 46113639Ssam if (callok(Rmtname) == SS_BADSEQ) { 46213639Ssam logent("BADSEQ", "PREVIOUS"); 46313639Ssam omsg('R', "BADSEQ", Ofn); 46413639Ssam cleanup(0); 46513639Ssam } 46617767Sralph #ifdef GNXSEQ 46713639Ssam if ((ret = gnxseq(Rmtname)) == seq) { 46813639Ssam omsg('R', "OK", Ofn); 46913639Ssam cmtseq(); 47017767Sralph } else { 47117767Sralph #else !GNXSEQ 47217767Sralph if (seq == 0) 47317767Sralph omsg('R', "OK", Ofn); 47413639Ssam else { 47517767Sralph #endif !GNXSEQ 47613639Ssam systat(Rmtname, Stattype[7], Stattext[7]); 47723590Sbloom logent("BAD SEQ", "FAILED HANDSHAKE"); 47817767Sralph #ifdef GNXSEQ 47913639Ssam ulkseq(); 48017767Sralph #endif GNXSEQ 48113639Ssam omsg('R', "BADSEQ", Ofn); 48213639Ssam cleanup(0); 48313639Ssam } 48413639Ssam if (ttyn != NULL) 48513639Ssam chmod(ttyn, 0600); 48613639Ssam } 48717767Sralph 48813639Ssam loop: 48917767Sralph if(setjmp(Pipebuf)) { /* come here on SIGPIPE */ 49017767Sralph clsacu(); 49134164Srick logcls(); 49217767Sralph close(Ofn); 49317767Sralph close(Ifn); 49417767Sralph Ifn = Ofn = -1; 49517767Sralph rmlock(CNULL); 49617767Sralph sleep(3); 49717767Sralph } 49813639Ssam if (!onesys) { 49933559Srick do_connect_accounting(); 50033945Srick #ifdef DIALINOUT 50133945Srick /* reenable logins on dialout */ 50233945Srick reenable(); 50333945Srick #endif DIALINOUT 50433559Srick StartTime = 0; 50534164Srick setproctitle("looking for work"); 50613639Ssam ret = gnsys(Rmtname, Spool, CMDPRE); 50734164Srick setproctitle("%s: startup", Rmtname); 50825703Sbloom setdebug(DBG_PERM); 50913639Ssam if (ret == FAIL) 51013639Ssam cleanup(100); 51133559Srick else if (ret == SUCCESS) 51213639Ssam cleanup(0); 51334164Srick logcls(); 51417767Sralph } else if (Role == MASTER && callok(Rmtname) != 0) { 51513639Ssam logent("SYSTEM STATUS", "CAN NOT CALL"); 51613639Ssam cleanup(0); 51713639Ssam } 51813639Ssam 51923590Sbloom sprintf(wkpre, "%c.%.*s", CMDPRE, SYSNSIZE, Rmtname); 52033559Srick StartTime = 0; 52133559Srick Bytes_Sent = Bytes_Received = 0L; 52213639Ssam 52317767Sralph signal(SIGINT, SIG_IGN); 52417767Sralph signal(SIGQUIT, SIG_IGN); 52513639Ssam if (Role == MASTER) { 52633559Srick extern char LineType[]; 52717767Sralph /* check for /etc/nologin */ 52825124Sbloom if (access(NOLOGIN, 0) == 0) { 52917767Sralph logent(NOLOGIN, "UUCICO SHUTDOWN"); 53023590Sbloom if (Debug > 4) 53117767Sralph logent("DEBUGGING", "continuing anyway"); 53217767Sralph else 53317767Sralph cleanup(1); 53417767Sralph } 53513639Ssam /* master part */ 53613639Ssam signal(SIGHUP, SIG_IGN); 53713639Ssam if (Ifn != -1 && Role == MASTER) { 53813639Ssam write(Ofn, EOTMSG, strlen(EOTMSG)); 53913639Ssam clsacu(); 54013639Ssam close(Ofn); 54113639Ssam close(Ifn); 54213639Ssam Ifn = Ofn = -1; 54313639Ssam rmlock(CNULL); 54413639Ssam sleep(3); 54513639Ssam } 54625124Sbloom if (mlock(Rmtname) != SUCCESS) { 54733559Srick DEBUG(1, "LOCKED: call to %s\n", Rmtname); 54817767Sralph US_SST(us_s_lock); 54913639Ssam goto next; 55013639Ssam } 55134164Srick setproctitle("%s: starting call", Rmtname); 55213639Ssam Ofn = Ifn = conn(Rmtname); 55334164Srick sprintf(msg, "(call to %s via %s)", Rmtname, LineType); 55413639Ssam if (Ofn < 0) { 55517767Sralph if (Ofn != CF_TIME) 55617767Sralph logent(msg, _FAILED); 55717767Sralph /* avoid excessive 'wrong time' info */ 55823590Sbloom if (Stattype[-Ofn] != SS_WRONGTIME){ 55917767Sralph systat(Rmtname, Stattype[-Ofn], Stattext[-Ofn]); 56017767Sralph US_SST(-Ofn); 56117767Sralph UB_SST(-Ofn); 56217767Sralph } 56313639Ssam goto next; 56417767Sralph } else { 56513639Ssam logent(msg, "SUCCEEDED"); 56617767Sralph US_SST(us_s_cok); 56717767Sralph UB_SST(ub_ok); 56813639Ssam } 56933559Srick InitialRole = MASTER; 57017767Sralph #ifdef TCPIP 57117767Sralph /* 57217767Sralph * Determine if we are on TCPIP 57317767Sralph */ 57425703Sbloom if (isatty(Ifn) == 0) { 57517767Sralph IsTcpIp = 1; 57617767Sralph DEBUG(4, "TCPIP connection -- ioctl-s disabled\n", CNULL); 57723590Sbloom } else 57823590Sbloom IsTcpIp = 0; 57917767Sralph #endif 58017767Sralph 58113639Ssam if (setjmp(Sjbuf)) 58213639Ssam goto next; 58313639Ssam signal(SIGALRM, timeout); 58433559Srick alarm(IsTcpIp?MAXMSGTIME*4:MAXMSGTIME*2); 58513639Ssam for (;;) { 58613639Ssam ret = imsg(msg, Ifn); 58733559Srick if (ret != SUCCESS) { 58813639Ssam alarm(0); 58933559Srick DEBUG(4,"\nimsg failed: errno %d\n", errno); 59017767Sralph logent("imsg 1", _FAILED); 59117767Sralph goto Failure; 59213639Ssam } 59313639Ssam if (msg[0] == 'S') 59413639Ssam break; 59513639Ssam } 59633559Srick alarm(IsTcpIp?MAXMSGTIME*4:MAXMSGTIME); 59717767Sralph #ifdef GNXSEQ 59813639Ssam seq = gnxseq(Rmtname); 59917767Sralph #else !GNXSEQ 60017767Sralph seq = 0; 60117767Sralph #endif !GNXSEQ 60218616Sralph if (MaxGrade != '\177') { 60323590Sbloom DEBUG(2, "Max Grade this transfer is %c\n", MaxGrade); 60425963Sbloom sprintf(msg, "%s -Q%d -p%c -vgrade=%c %s", 60525963Sbloom Myname, seq, MaxGrade, MaxGrade, rflags); 60625963Sbloom } else 60725963Sbloom sprintf(msg, "%s -Q%d %s", Myname, seq, rflags); 60813639Ssam omsg('S', msg, Ofn); 60913639Ssam for (;;) { 61013639Ssam ret = imsg(msg, Ifn); 61113639Ssam DEBUG(4, "msg-%s\n", msg); 61217767Sralph if (ret != SUCCESS) { 61313639Ssam alarm(0); 61417767Sralph #ifdef GNXSEQ 61513639Ssam ulkseq(); 61617767Sralph #endif GNXSEQ 61717767Sralph logent("imsg 2", _FAILED); 61817767Sralph goto Failure; 61913639Ssam } 62013639Ssam if (msg[0] == 'R') 62113639Ssam break; 62213639Ssam } 62313639Ssam alarm(0); 62413639Ssam if (msg[1] == 'B') { 62513639Ssam /* bad sequence */ 62623590Sbloom logent("BAD SEQ", "FAILED HANDSHAKE"); 62717767Sralph US_SST(us_s_hand); 62817767Sralph systat(Rmtname, SS_BADSEQ, Stattext[SS_BADSEQ]); 62917767Sralph #ifdef GNXSEQ 63013639Ssam ulkseq(); 63117767Sralph #endif GNXSEQ 63213639Ssam goto next; 63313639Ssam } 63413639Ssam if (strcmp(&msg[1], "OK") != SAME) { 63523590Sbloom logent(&msg[1], "FAILED HANDSHAKE"); 63617767Sralph US_SST(us_s_hand); 63717767Sralph #ifdef GNXSEQ 63813639Ssam ulkseq(); 63917767Sralph #endif GNXSEQ 64017767Sralph systat(Rmtname, SS_INPROGRESS, 64117767Sralph strcmp(&msg[1], "CB") == SAME? 64223590Sbloom "AWAITING CALLBACK": "FAILED HANDSHAKE"); 64313639Ssam goto next; 64413639Ssam } 64517767Sralph #ifdef GNXSEQ 64613639Ssam cmtseq(); 64717767Sralph #endif GNXSEQ 64813639Ssam } 64917767Sralph DEBUG(1, "Rmtname %s, ", Rmtname); 65013639Ssam DEBUG(1, "Role %s, ", Role ? "MASTER" : "SLAVE"); 65113639Ssam DEBUG(1, "Ifn - %d, ", Ifn); 65213639Ssam DEBUG(1, "Loginuser - %s\n", Loginuser); 65334164Srick setproctitle("%s: %s", Rmtname, Role ? "MASTER" : "SLAVE"); 65413639Ssam 65525703Sbloom ttyn = ttyname(Ifn); 65625703Sbloom 65733559Srick alarm(IsTcpIp?MAXMSGTIME*4:MAXMSGTIME); 65818616Sralph if (ret=setjmp(Sjbuf)) 65913639Ssam goto Failure; 66013639Ssam ret = startup(Role); 66113639Ssam alarm(0); 66213639Ssam if (ret != SUCCESS) { 66334164Srick logent("(startup)", _FAILED); 66413639Ssam Failure: 66517767Sralph US_SST(us_s_start); 66618616Sralph systat(Rmtname, SS_FAIL, ret > 0 ? "CONVERSATION FAILED" : 66718616Sralph "STARTUP FAILED"); 66813639Ssam goto next; 66917767Sralph } else { 67033559Srick char smsg[BUFSIZ], gmsg[10], pmsg[20], bpsmsg[20]; 67133559Srick extern char UsingProtocol; 67233559Srick extern int linebaudrate; 67333559Srick if (ttyn != NULL) 67433559Srick sprintf(bpsmsg, " %s %d bps", &ttyn[5], linebaudrate); 67533559Srick else 67633559Srick bpsmsg[0] = '\0'; 67733559Srick if (UsingProtocol != 'g') 67833559Srick sprintf(pmsg, " %c protocol", UsingProtocol); 67933559Srick else 68033559Srick pmsg[0] = '\0'; 68133559Srick if (MaxGrade != '\177') 68233559Srick sprintf(gmsg, " grade %c", MaxGrade); 68333559Srick else 68433559Srick gmsg[0] = '\0'; 68534164Srick sprintf(smsg, "(startup%s%s%s)", bpsmsg, pmsg, gmsg); 68633559Srick logent(smsg, "OK"); 68717767Sralph US_SST(us_s_gress); 68833559Srick StartTime = Now.time; 68913639Ssam systat(Rmtname, SS_INPROGRESS, "TALKING"); 69013639Ssam ret = cntrl(Role, wkpre); 69113639Ssam DEBUG(1, "cntrl - %d\n", ret); 69213639Ssam signal(SIGINT, SIG_IGN); 69313639Ssam signal(SIGHUP, SIG_IGN); 69413639Ssam signal(SIGALRM, timeout); 69534164Srick sprintf(smsg, "(conversation complete %ld sent %ld received)", 69633559Srick Bytes_Sent, Bytes_Received); 69717767Sralph if (ret == SUCCESS) { 69833559Srick logent(smsg, "OK"); 69917767Sralph US_SST(us_s_ok); 70013639Ssam rmstat(Rmtname); 70113639Ssam 70217767Sralph } else { 70333559Srick logent(smsg, _FAILED); 70417767Sralph US_SST(us_s_cf); 70517767Sralph systat(Rmtname, SS_FAIL, "CONVERSATION FAILED"); 70613639Ssam } 70733559Srick alarm(IsTcpIp?MAXMSGTIME*4:MAXMSGTIME); 70813639Ssam DEBUG(4, "send OO %d,", ret); 70913639Ssam if (!setjmp(Sjbuf)) { 71013639Ssam for (;;) { 71113639Ssam omsg('O', "OOOOO", Ofn); 71213639Ssam ret = imsg(msg, Ifn); 71313639Ssam if (ret != 0) 71413639Ssam break; 71513639Ssam if (msg[0] == 'O') 71613639Ssam break; 71713639Ssam } 71813639Ssam } 71913639Ssam alarm(0); 72017767Sralph clsacu(); 72117767Sralph rmlock(CNULL); 72233559Srick 72313639Ssam } 72413639Ssam next: 72513639Ssam if (!onesys) { 72613639Ssam goto loop; 72713639Ssam } 72813639Ssam cleanup(0); 72913639Ssam } 73013639Ssam 73117767Sralph #ifndef USG 73213639Ssam struct sgttyb Hupvec; 73313639Ssam #endif 73413639Ssam 73525703Sbloom /* 73625703Sbloom * cleanup and exit with "code" status 73713639Ssam */ 73813639Ssam cleanup(code) 73913639Ssam register int code; 74013639Ssam { 74113639Ssam signal(SIGINT, SIG_IGN); 74213639Ssam signal(SIGHUP, SIG_IGN); 74313639Ssam rmlock(CNULL); 74425703Sbloom sleep(5); /* Wait for any pending output */ 74513639Ssam clsacu(); 74613639Ssam logcls(); 74713639Ssam if (Role == SLAVE) { 74817767Sralph if (!IsTcpIp) { 74917767Sralph #ifdef USG 75013639Ssam Savettyb.c_cflag |= HUPCL; 75123590Sbloom (void) ioctl(0, TCSETA, &Savettyb); 75217767Sralph #else !USG 75323590Sbloom (void) ioctl(0, TIOCHPCL, STBNULL); 75418616Sralph #ifdef TIOCSDTR 75523590Sbloom (void) ioctl(0, TIOCCDTR, STBNULL); 75618616Sralph sleep(2); 75723590Sbloom (void) ioctl(0, TIOCSDTR, STBNULL); 75818616Sralph #else !TIOCSDTR 75923590Sbloom (void) ioctl(0, TIOCGETP, &Hupvec); 76013639Ssam Hupvec.sg_ispeed = B0; 76113639Ssam Hupvec.sg_ospeed = B0; 76223590Sbloom (void) ioctl(0, TIOCSETP, &Hupvec); 76325703Sbloom #endif !TIOCSDTR 76413639Ssam sleep(2); 76523590Sbloom (void) ioctl(0, TIOCSETP, &Savettyb); 76617767Sralph /* make *sure* exclusive access is off */ 76723590Sbloom (void) ioctl(0, TIOCNXCL, STBNULL); 76817767Sralph #endif !USG 76913639Ssam } 77013639Ssam if (ttyn != NULL) 77113639Ssam chmod(ttyn, 0600); 77213639Ssam } 77313639Ssam if (Ofn != -1) { 77413639Ssam if (Role == MASTER) 77513639Ssam write(Ofn, EOTMSG, strlen(EOTMSG)); 77613639Ssam close(Ifn); 77713639Ssam close(Ofn); 77813639Ssam } 77918616Sralph #ifdef DIALINOUT 78018616Sralph /* reenable logins on dialout */ 78118616Sralph reenable(); 78218616Sralph #endif DIALINOUT 78313639Ssam if (code == 0) 78413639Ssam xuuxqt(); 78517767Sralph else 78617767Sralph DEBUG(1, "exit code %d\n", code); 78725703Sbloom setdebug (DBG_CLEAN); 78833559Srick do_connect_accounting(); 78913639Ssam exit(code); 79013639Ssam } 79113639Ssam 79233559Srick do_connect_accounting() 79333559Srick { 79433945Srick #ifdef DO_CONNECT_ACCOUNTING 79533559Srick register FILE *fp; 79633559Srick struct tm *localtime(); 79733559Srick register struct tm *tm; 79833559Srick int flags; 79933559Srick 80033559Srick if (StartTime == 0) 80133559Srick return; 80233559Srick 80333945Srick fp = fopen(DO_CONNECT_ACCOUNTING, "a"); 80433945Srick if (fp == NULL) { 80533945Srick syslog(LOG_ALERT, "fopen(%s) failed: %m",DO_CONNECT_ACCOUNTING); 80633945Srick cleanup(FAIL); 80733945Srick } 80833559Srick 80933559Srick tm = localtime(&StartTime); 81033559Srick #ifdef F_SETFL 81133559Srick flags = fcntl(fileno(fp), F_GETFL, 0); 81233559Srick fcntl(fileno(fp), F_SETFL, flags|O_APPEND); 81333559Srick #endif 81433559Srick #ifdef USG 81533559Srick fprintf(fp,"%s %d %d%.2d%.2d %.2d%.2d %d %ld %s %ld %ld\n", 81633559Srick #else /* V7 */ 81733559Srick fprintf(fp,"%s %d %d%02d%02d %02d%02d %d %ld %s %ld %ld\n", 81833559Srick #endif /* V7 */ 81933559Srick Rmtname, InitialRole, tm->tm_year, tm->tm_mon + 1, 82033559Srick tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_wday, 82133559Srick (Now.time - StartTime + 59) / 60, 82233559Srick ttyn == NULL ? "ttyp0" : &ttyn[5], 82333559Srick Bytes_Sent, Bytes_Received); 82433559Srick fclose(fp); 82533559Srick #endif /* DO_CONNECT_ACCOUNTING */ 82633559Srick } 82733559Srick 82825703Sbloom /* 82925703Sbloom * on interrupt - remove locks and exit 83013639Ssam */ 83113639Ssam 83213639Ssam onintr(inter) 83313639Ssam register int inter; 83413639Ssam { 83533559Srick char str[BUFSIZ]; 83613639Ssam signal(inter, SIG_IGN); 83734164Srick sprintf(str, "(SIGNAL %d)", inter); 83813639Ssam logent(str, "CAUGHT"); 83917767Sralph US_SST(us_s_intr); 84023590Sbloom if (*Rmtname && strncmp(Rmtname, Myname, MAXBASENAME)) 84117767Sralph systat(Rmtname, SS_FAIL, str); 84234164Srick sprintf(str, "(conversation complete %ld sent %ld received)", 84333559Srick Bytes_Sent, Bytes_Received); 84433559Srick logent(str, _FAILED); 84517767Sralph if (inter == SIGPIPE && !onesys) 84617767Sralph longjmp(Pipebuf, 1); 84713639Ssam cleanup(inter); 84813639Ssam } 84913639Ssam 85013639Ssam /* 85113639Ssam * Catch a special signal 852*36449Smarc * (SIGUSR1), and toggle debugging between 0 and 30. 85313639Ssam * Handy for looking in on long running uucicos. 85413639Ssam */ 85525703Sbloom dbg_signal() 85613639Ssam { 85725703Sbloom Debug = (Debug == 0) ? 30 : 0; 85825703Sbloom setdebug(DBG_PERM); 85925703Sbloom if (Debug > 0) 86025703Sbloom logent("Signal Enabled", "DEBUG"); 86125703Sbloom } 86217767Sralph 86325703Sbloom 86425703Sbloom /* 86525703Sbloom * Check debugging requests, and open RMTDEBUG audit file if necessary. If an 86625703Sbloom * audit file is needed, the parm argument indicates how to create the file: 86725703Sbloom * 86825703Sbloom * DBG_TEMP - Open a temporary file, with filename = RMTDEBUG/pid. 86925703Sbloom * DBG_PERM - Open a permanent audit file, filename = RMTDEBUG/Rmtname. 87025703Sbloom * If a temp file already exists, it is mv'ed to be permanent. 87125703Sbloom * DBG_CLEAN - Cleanup; unlink temp files. 87225703Sbloom * 87325703Sbloom * Restrictions - this code can only cope with one open debug file at a time. 87425703Sbloom * Each call creates a new file; if an old one of the same name exists it will 87525703Sbloom * be overwritten. 87625703Sbloom */ 87725703Sbloom setdebug(parm) 87825703Sbloom int parm; 87925703Sbloom { 88025703Sbloom char buf[BUFSIZ]; /* Buffer for building filenames */ 88125703Sbloom static char *temp = NULL; /* Ptr to temporary file name */ 88225703Sbloom static int auditopen = 0; /* Set to 1 when we open a file */ 88325703Sbloom struct stat stbuf; /* File status buffer */ 88425703Sbloom 88525703Sbloom /* 88625703Sbloom * If movement or cleanup of a temp file is indicated, we do it no 88725703Sbloom * matter what. 88825703Sbloom */ 88925703Sbloom if (temp != CNULL && parm == DBG_PERM) { 89025703Sbloom sprintf(buf, "%s/%s", RMTDEBUG, Rmtname); 89125703Sbloom unlink(buf); 89225703Sbloom if (link(temp, buf) != 0) { 89323590Sbloom Debug = 0; 89433945Srick syslog(LOG_ERR, "RMTDEBUG link(%s,%s) failed: %m", 89533945Srick temp, buf); 89633945Srick cleanup(FAIL); 89725703Sbloom } 89825703Sbloom parm = DBG_CLEAN; 89923590Sbloom } 90025703Sbloom if (parm == DBG_CLEAN) { 90125703Sbloom if (temp != CNULL) { 90225703Sbloom unlink(temp); 90325703Sbloom free(temp); 90425703Sbloom temp = CNULL; 90525703Sbloom } 90625703Sbloom return; 90725703Sbloom } 90825703Sbloom 90925703Sbloom if (Debug == 0) 91025703Sbloom return; /* Gotta be in debug to come here. */ 91125703Sbloom 91225703Sbloom /* 91325703Sbloom * If we haven't opened a file already, we can just return if it's 91425703Sbloom * alright to use the stderr we came in with. We can if: 91525703Sbloom * 91625703Sbloom * Role == MASTER, and Stderr is a regular file, a TTY or a pipe. 91725703Sbloom * 91825703Sbloom * Caution: Detecting when stderr is a pipe is tricky, because the 4.2 91925703Sbloom * man page for fstat(2) disagrees with reality, and System V leaves it 92025703Sbloom * undefined, which means different implementations act differently. 92125703Sbloom */ 92225703Sbloom if (!auditopen && Role == MASTER) { 92325703Sbloom if (isatty(fileno(stderr))) 92425703Sbloom return; 92525703Sbloom else if (fstat(fileno(stderr), &stbuf) == 0) { 92625703Sbloom #ifdef USG 92725703Sbloom /* Is Regular File or Fifo */ 92825703Sbloom if ((stbuf.st_mode & 0060000) == 0) 92925703Sbloom return; 93025703Sbloom #else !USG 93117767Sralph #ifdef BSD4_2 93225703Sbloom /* Is Regular File */ 93325703Sbloom if ((stbuf.st_mode & S_IFMT) == S_IFREG || 93425703Sbloom stbuf.st_mode == 0) /* Is a pipe */ 93525703Sbloom return; 93625703Sbloom #else !BSD4_2 93725703Sbloom /* Is Regular File or Pipe */ 93825703Sbloom if ((stbuf.st_mode & S_IFMT) == S_IFREG) 93925703Sbloom return; 94025703Sbloom #endif BSD4_2 94125703Sbloom #endif USG 94225703Sbloom } 94317767Sralph } 94413639Ssam 94525703Sbloom /* 94625703Sbloom * We need RMTDEBUG directory to do auditing. If the file doesn't exist, 94725703Sbloom * then we forget about debugging; if it exists but has improper owner- 94825703Sbloom * ship or modes, we gripe about it in ERRLOG. 94925703Sbloom */ 95025703Sbloom if (stat(RMTDEBUG, &stbuf) != SUCCESS) { 95125703Sbloom Debug = 0; 95225703Sbloom return; 95325703Sbloom } 95425703Sbloom if ((geteuid() != stbuf.st_uid) || /* We must own it */ 95525703Sbloom ((stbuf.st_mode & 0170700) != 040700)) { /* Directory, rwx */ 95625703Sbloom Debug = 0; 95733945Srick syslog(LOG_ERR, "%s: invalid directory mode: %o", RMTDEBUG, 95833945Srick stbuf.st_mode); 95925703Sbloom return; 96025703Sbloom } 96113639Ssam 96225703Sbloom if (parm == DBG_TEMP) { 96325703Sbloom sprintf(buf, "%s/%d", RMTDEBUG, getpid()); 96425703Sbloom temp = malloc(strlen (buf) + 1); 96525703Sbloom if (temp == CNULL) { 96625703Sbloom Debug = 0; 96733945Srick syslog(LOG_ERR, "RMTDEBUG malloc failed: %m"); 96833945Srick cleanup(FAIL); 96925703Sbloom } 97025703Sbloom strcpy(temp, buf); 97125703Sbloom } else 97225703Sbloom sprintf(buf, "%s/%s", RMTDEBUG, Rmtname); 97313639Ssam 97425703Sbloom unlink(buf); 97525703Sbloom if (freopen(buf, "w", stderr) != stderr) { 97625703Sbloom Debug = 0; 97733945Srick syslog(LOG_ERR, "RMTDEBUG freopen(%s) failed: %m", buf); 97833945Srick cleanup(FAIL); 97925703Sbloom } 98025703Sbloom setbuf(stderr, CNULL); 98125703Sbloom auditopen = 1; 98213639Ssam } 98313639Ssam 98423590Sbloom /* 98525703Sbloom * catch SIGALRM routine 98613639Ssam */ 98713639Ssam timeout() 98813639Ssam { 98923590Sbloom extern int HaveSentHup; 99023590Sbloom if (!HaveSentHup) { 99123590Sbloom logent(Rmtname, "TIMEOUT"); 99223590Sbloom if (*Rmtname && strncmp(Rmtname, Myname, MAXBASENAME)) { 99323590Sbloom US_SST(us_s_tmot); 99423590Sbloom systat(Rmtname, SS_FAIL, "TIMEOUT"); 99523590Sbloom } 99617767Sralph } 99713639Ssam longjmp(Sjbuf, 1); 99813639Ssam } 99913639Ssam 100013639Ssam static char * 100113639Ssam pskip(p) 100213639Ssam register char *p; 100313639Ssam { 100417767Sralph while(*p && *p != ' ') 100513639Ssam ++p; 100623590Sbloom while(*p && *p == ' ') 100717767Sralph *p++ = 0; 100817767Sralph return p; 100913639Ssam } 101034164Srick 101134164Srick /* 101234164Srick * clobber argv so ps will show what we're doing. 101334164Srick * stolen from sendmail 101434164Srick */ 101534164Srick /*VARARGS1*/ 101634164Srick setproctitle(fmt, a, b, c) 101734164Srick char *fmt; 101834164Srick { 101934164Srick #ifdef SETPROCTITLE 102034164Srick register char *p; 102134164Srick register int i; 102234164Srick extern char **Argv; 102334164Srick extern char *LastArgv; 102434164Srick char buf[BUFSIZ]; 102534164Srick 102634164Srick (void) sprintf(buf, fmt, a, b, c); 102734164Srick 102834164Srick /* make ps print "(sendmail)" */ 102934164Srick p = Argv[0]; 103034164Srick *p++ = '-'; 103134164Srick 103234164Srick i = strlen(buf); 103334164Srick if (i > LastArgv - p - 2) { 103434164Srick i = LastArgv - p - 2; 103534164Srick buf[i] = '\0'; 103634164Srick } 103734164Srick (void) strcpy(p, buf); 103834164Srick p += i; 103934164Srick while (p < LastArgv) 104034164Srick *p++ = ' '; 104134164Srick #endif SETPROCTITLE 104234164Srick } 1043