113639Ssam #ifndef lint 2*46879Sbostic static char sccsid[] = "@(#)cico.c 5.20 (Berkeley) 03/02/91"; 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" 2937930Sbostic #include "pathnames.h" 3013639Ssam 3123590Sbloom #if defined(VMS) && defined(BSDTCP) 3223590Sbloom #define NOGETPEER 3323590Sbloom #endif 3423590Sbloom 3517767Sralph jmp_buf Sjbuf; 3617767Sralph jmp_buf Pipebuf; 3713639Ssam 3817767Sralph /* call fail text */ 3913639Ssam char *Stattext[] = { 4013639Ssam "", 4113639Ssam "BAD SYSTEM", 4217767Sralph "WRONG TIME TO CALL", 4313639Ssam "SYSTEM LOCKED", 4413639Ssam "NO DEVICE", 4525703Sbloom "CALL FAILED", 4613639Ssam "LOGIN FAILED", 4713639Ssam "BAD SEQUENCE" 4817767Sralph }; 4913639Ssam 5017767Sralph /* call fail codes */ 5117767Sralph int Stattype[] = { 5217767Sralph 0, 5317767Sralph 0, 5417767Sralph SS_WRONGTIME, 5517767Sralph 0, 5617767Sralph SS_NODEVICE, 5717767Sralph SS_FAIL, 5817767Sralph SS_FAIL, 5917767Sralph SS_BADSEQ 6017767Sralph }; 6113639Ssam 6225703Sbloom /* Arguments to setdebug(): */ 6325703Sbloom #define DBG_TEMP 0 /* Create a temporary audit file */ 6425703Sbloom #define DBG_PERM 1 /* Create a permanent audit file */ 6525703Sbloom #define DBG_CLEAN 2 /* Cleanup, discard temp file */ 6613639Ssam 6717767Sralph int ReverseRole = 0; 6817767Sralph int Role = SLAVE; 6933559Srick int InitialRole = SLAVE; 7033559Srick long StartTime; 7117767Sralph int onesys = 0; 7218616Sralph int turntime = 30 * 60; /* 30 minutes expressed in seconds */ 7325703Sbloom char *ttyn = NULL; 7417767Sralph extern int LocalOnly; 7525703Sbloom extern int errno; 7618616Sralph extern char MaxGrade, DefMaxGrade; 7718616Sralph extern char Myfullname[]; 7817767Sralph 7933559Srick long Bytes_Sent, Bytes_Received; 8033559Srick 8117767Sralph #ifdef USG 8213639Ssam struct termio Savettyb; 8313639Ssam #endif 8417767Sralph #ifndef USG 8513639Ssam struct sgttyb Savettyb; 8613639Ssam #endif 8713639Ssam 8834164Srick #define SETPROCTITLE 8934164Srick #ifdef SETPROCTITLE 9034164Srick char **Argv = NULL; /* pointer to argument vector */ 9134164Srick char *LastArgv = NULL; /* end of argv */ 9234164Srick #endif SETPROCTITLE 9334164Srick 9425703Sbloom /* 9525703Sbloom * this program is used to place a call to a 9613639Ssam * remote machine, login, and copy files between the two machines. 9713639Ssam */ 9834164Srick main(argc, argv, envp) 9925703Sbloom int argc; 10033945Srick char **argv; 10134164Srick char **envp; 10213639Ssam { 10313639Ssam register int ret; 10413639Ssam int seq; 10513639Ssam char wkpre[NAMESIZE], file[NAMESIZE]; 10625703Sbloom char msg[MAXFULLNAME], *q; 10713639Ssam register char *p; 108*46879Sbostic static void onintr(), timeout(), dbg_signal(); 109*46879Sbostic static char *pskip(); 11033945Srick extern char *optarg; 11133945Srick extern int optind; 11223725Sbloom char rflags[MAXFULLNAME]; 11323590Sbloom #ifdef NOGETPEER 11417767Sralph u_long Hostnumber = 0; 11523590Sbloom #endif NOGETPEER 11613639Ssam 11713639Ssam strcpy(Progname, "uucico"); 11813639Ssam 11926149Sbloom #ifdef BSD4_2 12033945Srick sigsetmask(0L); /* in case we inherit blocked signals */ 12126149Sbloom #endif BSD4_2 12213639Ssam signal(SIGINT, onintr); 12313639Ssam signal(SIGHUP, onintr); 12413639Ssam signal(SIGQUIT, onintr); 12513639Ssam signal(SIGTERM, onintr); 12613639Ssam signal(SIGPIPE, onintr); /* 4.1a tcp-ip stupidity */ 12736449Smarc signal(SIGUSR1, dbg_signal); 12813639Ssam ret = guinfo(getuid(), User, msg); 12913639Ssam strcpy(Loginuser, User); 13023590Sbloom uucpname(Myname); 13133945Srick if (ret == FAIL) { 13233945Srick syslog(LOG_ERR, "can't get uid"); 13333945Srick cleanup(FAIL); 13433945Srick } 13513639Ssam 13625703Sbloom setbuf (stderr, CNULL); 13725703Sbloom 13825703Sbloom rflags[0] = '\0'; 13913639Ssam umask(WFMASK); 14013639Ssam strcpy(Rmtname, Myname); 14113639Ssam Ifn = Ofn = -1; 14233945Srick while ((ret = getopt(argc, argv, "RLd:g:p:r:s:x:t:")) != EOF) 14333945Srick switch(ret){ 14413639Ssam case 'd': 14533945Srick Spool = optarg; 14613639Ssam break; 14713639Ssam case 'g': 14818616Sralph case 'p': 14933945Srick MaxGrade = DefMaxGrade = *optarg; 15013639Ssam break; 15113639Ssam case 'r': 15233945Srick Role = atoi(optarg); 15313639Ssam break; 15417767Sralph case 'R': 15517767Sralph ReverseRole++; 15617767Sralph Role = MASTER; 15717767Sralph break; 15813639Ssam case 's': 15933945Srick strncpy(Rmtname, optarg, MAXBASENAME); 16023590Sbloom Rmtname[MAXBASENAME] = '\0'; 16113639Ssam if (Rmtname[0] != '\0') 16213639Ssam onesys = 1; 16313639Ssam break; 16413639Ssam case 'x': 16533945Srick Debug = atoi(optarg); 16613639Ssam if (Debug <= 0) 16713639Ssam Debug = 1; 16833945Srick strcat(rflags, argv[optind-1]); 16913639Ssam break; 17018616Sralph case 't': 17133945Srick turntime = atoi(optarg)*60;/* minutes to seconds */ 17218616Sralph break; 17317767Sralph case 'L': /* local calls only */ 17417767Sralph LocalOnly++; 17517767Sralph break; 17623590Sbloom #ifdef NOGETPEER 17717767Sralph case 'h': 17817767Sralph Hostnumber = inet_addr(&argv[1][2]); 17917767Sralph break; 18023590Sbloom #endif NOGETPEER 18133945Srick case '?': 18213639Ssam default: 18333945Srick fprintf(stderr, "unknown flag %s (ignored)\n", 18433945Srick argv[optind-1]); 18513639Ssam break; 18613639Ssam } 18713639Ssam 18833945Srick while (optind < argc) 18933945Srick fprintf(stderr, "unknown argument %s (ignored)\n", 19033945Srick argv[optind++]); 19117767Sralph 19227069Sbloom if (Debug && Role == MASTER) 19327069Sbloom chkdebug(); 19427069Sbloom 19534164Srick #ifdef SETPROCTITLE 19634164Srick /* 19734164Srick * Save start and extent of argv for setproctitle. 19834164Srick */ 19934164Srick 20034164Srick Argv = argv; 20134164Srick LastArgv = argv[argc - 1] + strlen(argv[argc - 1]); 20234164Srick #endif SETPROCTITLE 20334164Srick 20425124Sbloom /* Try to run as uucp */ 20517767Sralph setgid(getegid()); 20617767Sralph setuid(geteuid()); 20717767Sralph #ifdef TIOCNOTTY 20817767Sralph /* 20917767Sralph * detach uucico from controlling terminal 21017767Sralph * to defend against rlogind sending us a SIGKILL (!!!) 21117767Sralph */ 21237930Sbostic if (Role == MASTER && (ret = open(_PATH_TTY, 2)) >= 0) { 21317767Sralph ioctl(ret, TIOCNOTTY, STBNULL); 21417767Sralph close(ret); 21517767Sralph } 21617767Sralph #endif TIOCNOTTY 21717767Sralph #ifdef BSD4_2 21825517Stef if (getpgrp(0) == 0) { /* We have no controlling terminal */ 21917767Sralph setpgrp(0, getpid()); 22017767Sralph } 22133945Srick #ifdef USE_SYSLOG 22233945Srick #ifdef BSD4_3 22333945Srick openlog("uucico", LOG_PID, LOG_UUCP); 22433945Srick #else /* !BSD4_3 */ 22533945Srick openlog("uucico", LOG_PID); 22633945Srick #endif /* !BSD4_3 */ 22733945Srick #endif /* USE_SYSLOG */ 22817767Sralph #endif BSD4_2 22917767Sralph 23033945Srick #ifdef BSD4_3 23133945Srick unsetenv("TZ"); /* We don't want him resetting our time zone */ 23233945Srick #endif /* !BSD4_3 */ 23333945Srick 23433945Srick if (subchdir(Spool) < 0) { 23533945Srick syslog(LOG_ERR, "chdir(%s) failed: %m", Spool); 23633945Srick cleanup(FAIL); 23733945Srick } 23833945Srick 23913639Ssam strcpy(Wrkdir, Spool); 24013639Ssam 24125703Sbloom if (Debug) { 24225703Sbloom setdebug ((Role == SLAVE) ? DBG_TEMP : DBG_PERM); 24325703Sbloom if (Debug > 0) 24425703Sbloom logent ("Local Enabled", "DEBUG"); 24525703Sbloom } 24625703Sbloom 24725703Sbloom /* 24825703Sbloom * First time through: If we're the slave, do initial checking. 24925703Sbloom */ 25013639Ssam if (Role == SLAVE) { 25117767Sralph /* check for /etc/nologin */ 25225124Sbloom if (access(NOLOGIN, 0) == 0) { 25317767Sralph logent(NOLOGIN, "UUCICO SHUTDOWN"); 25423590Sbloom if (Debug > 4) 25517767Sralph logent("DEBUGGING", "continuing anyway"); 25617767Sralph else 25717767Sralph cleanup(1); 25817767Sralph } 25925703Sbloom Ifn = 0; 26025703Sbloom Ofn = 1; 26117767Sralph #ifdef TCPIP 26217767Sralph /* 26317767Sralph * Determine if we are on TCPIP 26417767Sralph */ 26533559Srick if (isatty(Ifn) == 0) { 26617767Sralph IsTcpIp = 1; 26717767Sralph DEBUG(4, "TCPIP connection -- ioctl-s disabled\n", CNULL); 26823590Sbloom } else 26923590Sbloom IsTcpIp = 0; 27017767Sralph #endif TCPIP 27113639Ssam /* initial handshake */ 27213639Ssam onesys = 1; 27317767Sralph if (!IsTcpIp) { 27417767Sralph #ifdef USG 27525703Sbloom ret = ioctl(Ifn, TCGETA, &Savettyb); 27613639Ssam Savettyb.c_cflag = (Savettyb.c_cflag & ~CS8) | CS7; 27713639Ssam Savettyb.c_oflag |= OPOST; 27813639Ssam Savettyb.c_lflag |= (ISIG|ICANON|ECHO); 27917767Sralph #else !USG 28025703Sbloom ret = ioctl(Ifn, TIOCGETP, &Savettyb); 28113639Ssam Savettyb.sg_flags |= ECHO; 28213639Ssam Savettyb.sg_flags &= ~RAW; 28317767Sralph #endif !USG 28425703Sbloom ttyn = ttyname(Ifn); 28513639Ssam } 28613639Ssam fixmode(Ifn); 28725703Sbloom 28825703Sbloom /* 28925703Sbloom * Initial Message -- tell them we're here, and who we are. 29025703Sbloom */ 29118616Sralph sprintf(msg, "here=%s", Myfullname); 29217767Sralph omsg('S', msg, Ofn); 29313639Ssam signal(SIGALRM, timeout); 29433559Srick alarm(IsTcpIp?MAXMSGTIME*4:MAXMSGTIME); 29513639Ssam if (setjmp(Sjbuf)) { 29613639Ssam /* timed out */ 29717767Sralph if (!IsTcpIp) { 29817767Sralph #ifdef USG 29925703Sbloom ret = ioctl(Ifn, TCSETA, &Savettyb); 30025703Sbloom 30123590Sbloom #else !USG 30225703Sbloom ret = ioctl(Ifn, TIOCSETP, &Savettyb); 30323590Sbloom #endif !USG 30413639Ssam } 30517767Sralph cleanup(0); 30613639Ssam } 30713639Ssam for (;;) { 30813639Ssam ret = imsg(msg, Ifn); 30925703Sbloom if (ret != SUCCESS) { 31013639Ssam alarm(0); 31117767Sralph if (!IsTcpIp) { 31217767Sralph #ifdef USG 31325703Sbloom ret = ioctl(Ifn, TCSETA, &Savettyb); 31423590Sbloom #else !USG 31525703Sbloom ret = ioctl(Ifn, TIOCSETP, &Savettyb); 31623590Sbloom #endif !USG 31713639Ssam } 31817767Sralph cleanup(0); 31913639Ssam } 32013639Ssam if (msg[0] == 'S') 32113639Ssam break; 32213639Ssam } 32313639Ssam alarm(0); 32413639Ssam q = &msg[1]; 32513639Ssam p = pskip(q); 32623590Sbloom strncpy(Rmtname, q, MAXBASENAME); 32723590Sbloom Rmtname[MAXBASENAME] = '\0'; 32825703Sbloom 32925703Sbloom /* 33025703Sbloom * Now that we know who they are, give the audit file the right 33125703Sbloom * name. 33225703Sbloom */ 33325703Sbloom setdebug (DBG_PERM); 33413639Ssam DEBUG(4, "sys-%s\n", Rmtname); 33523725Sbloom /* The versys will also do an alias on the incoming name */ 33623725Sbloom if (versys(&Rmtname)) { 33733559Srick #ifdef NOSTRANGERS 33823725Sbloom /* If we don't know them, we won't talk to them... */ 33933945Srick syslog(LOG_WARNING, "Unknown host: %s", Rmtname); 34023590Sbloom omsg('R', "You are unknown to me", Ofn); 34123590Sbloom cleanup(0); 34223725Sbloom #endif NOSTRANGERS 34323590Sbloom } 34417767Sralph #ifdef BSDTCP 34517767Sralph /* we must make sure they are really who they say they 34617767Sralph * are. We compare the hostnumber with the number in the hosts 34717767Sralph * table for the site they claim to be. 34817767Sralph */ 34917767Sralph if (IsTcpIp) { 35017767Sralph struct hostent *hp; 35117767Sralph char *cpnt, *inet_ntoa(); 35225703Sbloom int fromlen; 35317767Sralph struct sockaddr_in from; 35425124Sbloom extern char PhoneNumber[]; 35517767Sralph 35623590Sbloom #ifdef NOGETPEER 35723590Sbloom from.sin_addr.s_addr = Hostnumber; 35823590Sbloom from.sin_family = AF_INET; 35923590Sbloom #else !NOGETPEER 36025703Sbloom fromlen = sizeof(from); 361*46879Sbostic if (getpeername(Ifn, 362*46879Sbostic (struct sockaddr *)&from, &fromlen) < 0) { 36317767Sralph logent(Rmtname, "NOT A TCP CONNECTION"); 36417767Sralph omsg('R', "NOT TCP", Ofn); 36517767Sralph cleanup(0); 36617767Sralph } 36723590Sbloom #endif !NOGETPEER 368*46879Sbostic hp = gethostbyaddr((char *)&from.sin_addr, 36917767Sralph sizeof (struct in_addr), from.sin_family); 37025703Sbloom if (hp == NULL) { 37117767Sralph /* security break or just old host table? */ 37217767Sralph logent(Rmtname, "UNKNOWN IP-HOST Name ="); 37317767Sralph cpnt = inet_ntoa(from.sin_addr), 37417767Sralph logent(cpnt, "UNKNOWN IP-HOST Number ="); 37517767Sralph sprintf(wkpre, "%s/%s isn't in my host table", 37617767Sralph Rmtname, cpnt); 37717767Sralph omsg('R' ,wkpre ,Ofn); 37817767Sralph cleanup(0); 37917767Sralph } 38025703Sbloom if (Debug > 99) 38117767Sralph logent(Rmtname,"Request from IP-Host name ="); 38225124Sbloom /* 38325124Sbloom * The following is to determine if the name given us by 38425124Sbloom * the Remote uucico matches any of the names 38517767Sralph * given its network number (remote machine) in our 38617767Sralph * host table. 38725124Sbloom * We could check the aliases, but that won't work in 38825124Sbloom * all cases (like if you are running the domain 38925124Sbloom * server, where you don't get any aliases). The only 39025124Sbloom * reliable way I can think of that works in ALL cases 39125124Sbloom * is too look up the site in L.sys and see if the 39225124Sbloom * sitename matches what we would call him if we 39325124Sbloom * originated the call. 39417767Sralph */ 39525124Sbloom /* PhoneNumber contains the official network name of the host we are checking. (set in versys.c) */ 39625124Sbloom if (sncncmp(PhoneNumber, hp->h_name, SYSNSIZE) == 0) { 39717767Sralph if (Debug > 99) 39817767Sralph logent(q,"Found in host Tables"); 39925124Sbloom } else { 40025124Sbloom logent(hp->h_name, "FORGED HOSTNAME"); 40125124Sbloom logent(inet_ntoa(from.sin_addr), "ORIGINATED AT"); 40225124Sbloom logent(PhoneNumber, "SHOULD BE"); 40325124Sbloom sprintf(wkpre, "You're not who you claim to be: %s != %s", hp->h_name, PhoneNumber); 40425124Sbloom omsg('R', wkpre, Ofn); 40525124Sbloom cleanup(0); 40617767Sralph } 40717767Sralph } 40817767Sralph #endif BSDTCP 40917767Sralph 41025703Sbloom if (mlock(Rmtname)) { 41113639Ssam omsg('R', "LCK", Ofn); 41213639Ssam cleanup(0); 41313639Ssam } 41413639Ssam else if (callback(Loginuser)) { 41513639Ssam signal(SIGINT, SIG_IGN); 41613639Ssam signal(SIGHUP, SIG_IGN); 41713639Ssam omsg('R', "CB", Ofn); 41813639Ssam logent("CALLBACK", "REQUIRED"); 41913639Ssam /* set up for call back */ 42017767Sralph systat(Rmtname, SS_CALLBACK, "CALLING BACK"); 42113639Ssam gename(CMDPRE, Rmtname, 'C', file); 42213639Ssam close(creat(subfile(file), 0666)); 42313639Ssam xuucico(Rmtname); 42413639Ssam cleanup(0); 42513639Ssam } 42613639Ssam seq = 0; 42713639Ssam while (*p == '-') { 42813639Ssam q = pskip(p); 42913639Ssam switch(*(++p)) { 43013639Ssam case 'x': 43125703Sbloom if (Debug == 0) { 43225703Sbloom Debug = atoi(++p); 43325703Sbloom if (Debug <= 0) 43425703Sbloom Debug = 1; 43525703Sbloom setdebug(DBG_PERM); 43625703Sbloom if (Debug > 0) 43725703Sbloom logent("Remote Enabled", "DEBUG"); 43825703Sbloom } else { 43925703Sbloom DEBUG(1, "Remote debug request ignored\n", 44025703Sbloom CNULL); 44125703Sbloom } 44213639Ssam break; 44313639Ssam case 'Q': 44413639Ssam seq = atoi(++p); 44513639Ssam break; 44618616Sralph case 'p': 44718616Sralph MaxGrade = DefMaxGrade = *++p; 44818616Sralph DEBUG(4, "MaxGrade set to %c\n", MaxGrade); 44918616Sralph break; 45023590Sbloom case 'v': 45123590Sbloom if (strncmp(p, "grade", 5) == 0) { 45223590Sbloom p += 6; 45323590Sbloom MaxGrade = DefMaxGrade = *p++; 45423590Sbloom DEBUG(4, "MaxGrade set to %c\n", MaxGrade); 45523590Sbloom } 45623590Sbloom break; 45713639Ssam default: 45813639Ssam break; 45913639Ssam } 46013639Ssam p = q; 46113639Ssam } 46234164Srick setproctitle("%s: startup", Rmtname); 46313639Ssam if (callok(Rmtname) == SS_BADSEQ) { 46413639Ssam logent("BADSEQ", "PREVIOUS"); 46513639Ssam omsg('R', "BADSEQ", Ofn); 46613639Ssam cleanup(0); 46713639Ssam } 46817767Sralph #ifdef GNXSEQ 46913639Ssam if ((ret = gnxseq(Rmtname)) == seq) { 47013639Ssam omsg('R', "OK", Ofn); 47113639Ssam cmtseq(); 47217767Sralph } else { 47317767Sralph #else !GNXSEQ 47417767Sralph if (seq == 0) 47517767Sralph omsg('R', "OK", Ofn); 47613639Ssam else { 47717767Sralph #endif !GNXSEQ 47813639Ssam systat(Rmtname, Stattype[7], Stattext[7]); 47923590Sbloom logent("BAD SEQ", "FAILED HANDSHAKE"); 48017767Sralph #ifdef GNXSEQ 48113639Ssam ulkseq(); 48217767Sralph #endif GNXSEQ 48313639Ssam omsg('R', "BADSEQ", Ofn); 48413639Ssam cleanup(0); 48513639Ssam } 48613639Ssam if (ttyn != NULL) 48713639Ssam chmod(ttyn, 0600); 48813639Ssam } 48917767Sralph 49013639Ssam loop: 49117767Sralph if(setjmp(Pipebuf)) { /* come here on SIGPIPE */ 49217767Sralph clsacu(); 49334164Srick logcls(); 49417767Sralph close(Ofn); 49517767Sralph close(Ifn); 49617767Sralph Ifn = Ofn = -1; 49717767Sralph rmlock(CNULL); 49817767Sralph sleep(3); 49917767Sralph } 50013639Ssam if (!onesys) { 50133559Srick do_connect_accounting(); 50233945Srick #ifdef DIALINOUT 50333945Srick /* reenable logins on dialout */ 50433945Srick reenable(); 50533945Srick #endif DIALINOUT 50633559Srick StartTime = 0; 50734164Srick setproctitle("looking for work"); 50813639Ssam ret = gnsys(Rmtname, Spool, CMDPRE); 50934164Srick setproctitle("%s: startup", Rmtname); 51025703Sbloom setdebug(DBG_PERM); 51113639Ssam if (ret == FAIL) 51213639Ssam cleanup(100); 51333559Srick else if (ret == SUCCESS) 51413639Ssam cleanup(0); 51534164Srick logcls(); 51617767Sralph } else if (Role == MASTER && callok(Rmtname) != 0) { 51713639Ssam logent("SYSTEM STATUS", "CAN NOT CALL"); 51813639Ssam cleanup(0); 51913639Ssam } 52013639Ssam 52123590Sbloom sprintf(wkpre, "%c.%.*s", CMDPRE, SYSNSIZE, Rmtname); 52233559Srick StartTime = 0; 52333559Srick Bytes_Sent = Bytes_Received = 0L; 52413639Ssam 52517767Sralph signal(SIGINT, SIG_IGN); 52617767Sralph signal(SIGQUIT, SIG_IGN); 52713639Ssam if (Role == MASTER) { 52833559Srick extern char LineType[]; 52917767Sralph /* check for /etc/nologin */ 53025124Sbloom if (access(NOLOGIN, 0) == 0) { 53117767Sralph logent(NOLOGIN, "UUCICO SHUTDOWN"); 53223590Sbloom if (Debug > 4) 53317767Sralph logent("DEBUGGING", "continuing anyway"); 53417767Sralph else 53517767Sralph cleanup(1); 53617767Sralph } 53713639Ssam /* master part */ 53813639Ssam signal(SIGHUP, SIG_IGN); 53913639Ssam if (Ifn != -1 && Role == MASTER) { 54013639Ssam write(Ofn, EOTMSG, strlen(EOTMSG)); 54113639Ssam clsacu(); 54213639Ssam close(Ofn); 54313639Ssam close(Ifn); 54413639Ssam Ifn = Ofn = -1; 54513639Ssam rmlock(CNULL); 54613639Ssam sleep(3); 54713639Ssam } 54825124Sbloom if (mlock(Rmtname) != SUCCESS) { 54933559Srick DEBUG(1, "LOCKED: call to %s\n", Rmtname); 55017767Sralph US_SST(us_s_lock); 55113639Ssam goto next; 55213639Ssam } 55334164Srick setproctitle("%s: starting call", Rmtname); 55413639Ssam Ofn = Ifn = conn(Rmtname); 55534164Srick sprintf(msg, "(call to %s via %s)", Rmtname, LineType); 55613639Ssam if (Ofn < 0) { 55717767Sralph if (Ofn != CF_TIME) 55817767Sralph logent(msg, _FAILED); 55917767Sralph /* avoid excessive 'wrong time' info */ 56023590Sbloom if (Stattype[-Ofn] != SS_WRONGTIME){ 56117767Sralph systat(Rmtname, Stattype[-Ofn], Stattext[-Ofn]); 56217767Sralph US_SST(-Ofn); 56317767Sralph UB_SST(-Ofn); 56417767Sralph } 56513639Ssam goto next; 56617767Sralph } else { 56713639Ssam logent(msg, "SUCCEEDED"); 56817767Sralph US_SST(us_s_cok); 56917767Sralph UB_SST(ub_ok); 57013639Ssam } 57133559Srick InitialRole = MASTER; 57217767Sralph #ifdef TCPIP 57317767Sralph /* 57417767Sralph * Determine if we are on TCPIP 57517767Sralph */ 57625703Sbloom if (isatty(Ifn) == 0) { 57717767Sralph IsTcpIp = 1; 57817767Sralph DEBUG(4, "TCPIP connection -- ioctl-s disabled\n", CNULL); 57923590Sbloom } else 58023590Sbloom IsTcpIp = 0; 58117767Sralph #endif 58217767Sralph 58313639Ssam if (setjmp(Sjbuf)) 58413639Ssam goto next; 58513639Ssam signal(SIGALRM, timeout); 58633559Srick alarm(IsTcpIp?MAXMSGTIME*4:MAXMSGTIME*2); 58713639Ssam for (;;) { 58813639Ssam ret = imsg(msg, Ifn); 58933559Srick if (ret != SUCCESS) { 59013639Ssam alarm(0); 59133559Srick DEBUG(4,"\nimsg failed: errno %d\n", errno); 59217767Sralph logent("imsg 1", _FAILED); 59317767Sralph goto Failure; 59413639Ssam } 59513639Ssam if (msg[0] == 'S') 59613639Ssam break; 59713639Ssam } 59833559Srick alarm(IsTcpIp?MAXMSGTIME*4:MAXMSGTIME); 59917767Sralph #ifdef GNXSEQ 60013639Ssam seq = gnxseq(Rmtname); 60117767Sralph #else !GNXSEQ 60217767Sralph seq = 0; 60317767Sralph #endif !GNXSEQ 60418616Sralph if (MaxGrade != '\177') { 60523590Sbloom DEBUG(2, "Max Grade this transfer is %c\n", MaxGrade); 60625963Sbloom sprintf(msg, "%s -Q%d -p%c -vgrade=%c %s", 60725963Sbloom Myname, seq, MaxGrade, MaxGrade, rflags); 60825963Sbloom } else 60925963Sbloom sprintf(msg, "%s -Q%d %s", Myname, seq, rflags); 61013639Ssam omsg('S', msg, Ofn); 61113639Ssam for (;;) { 61213639Ssam ret = imsg(msg, Ifn); 61313639Ssam DEBUG(4, "msg-%s\n", msg); 61417767Sralph if (ret != SUCCESS) { 61513639Ssam alarm(0); 61617767Sralph #ifdef GNXSEQ 61713639Ssam ulkseq(); 61817767Sralph #endif GNXSEQ 61917767Sralph logent("imsg 2", _FAILED); 62017767Sralph goto Failure; 62113639Ssam } 62213639Ssam if (msg[0] == 'R') 62313639Ssam break; 62413639Ssam } 62513639Ssam alarm(0); 62613639Ssam if (msg[1] == 'B') { 62713639Ssam /* bad sequence */ 62823590Sbloom logent("BAD SEQ", "FAILED HANDSHAKE"); 62917767Sralph US_SST(us_s_hand); 63017767Sralph systat(Rmtname, SS_BADSEQ, Stattext[SS_BADSEQ]); 63117767Sralph #ifdef GNXSEQ 63213639Ssam ulkseq(); 63317767Sralph #endif GNXSEQ 63413639Ssam goto next; 63513639Ssam } 63613639Ssam if (strcmp(&msg[1], "OK") != SAME) { 63723590Sbloom logent(&msg[1], "FAILED HANDSHAKE"); 63817767Sralph US_SST(us_s_hand); 63917767Sralph #ifdef GNXSEQ 64013639Ssam ulkseq(); 64117767Sralph #endif GNXSEQ 64217767Sralph systat(Rmtname, SS_INPROGRESS, 64317767Sralph strcmp(&msg[1], "CB") == SAME? 64423590Sbloom "AWAITING CALLBACK": "FAILED HANDSHAKE"); 64513639Ssam goto next; 64613639Ssam } 64717767Sralph #ifdef GNXSEQ 64813639Ssam cmtseq(); 64917767Sralph #endif GNXSEQ 65013639Ssam } 65117767Sralph DEBUG(1, "Rmtname %s, ", Rmtname); 65213639Ssam DEBUG(1, "Role %s, ", Role ? "MASTER" : "SLAVE"); 65313639Ssam DEBUG(1, "Ifn - %d, ", Ifn); 65413639Ssam DEBUG(1, "Loginuser - %s\n", Loginuser); 65534164Srick setproctitle("%s: %s", Rmtname, Role ? "MASTER" : "SLAVE"); 65613639Ssam 65725703Sbloom ttyn = ttyname(Ifn); 65825703Sbloom 65933559Srick alarm(IsTcpIp?MAXMSGTIME*4:MAXMSGTIME); 66018616Sralph if (ret=setjmp(Sjbuf)) 66113639Ssam goto Failure; 66213639Ssam ret = startup(Role); 66313639Ssam alarm(0); 66413639Ssam if (ret != SUCCESS) { 66534164Srick logent("(startup)", _FAILED); 66613639Ssam Failure: 66717767Sralph US_SST(us_s_start); 66818616Sralph systat(Rmtname, SS_FAIL, ret > 0 ? "CONVERSATION FAILED" : 66918616Sralph "STARTUP FAILED"); 67013639Ssam goto next; 67117767Sralph } else { 67233559Srick char smsg[BUFSIZ], gmsg[10], pmsg[20], bpsmsg[20]; 67333559Srick extern char UsingProtocol; 67433559Srick extern int linebaudrate; 67533559Srick if (ttyn != NULL) 67633559Srick sprintf(bpsmsg, " %s %d bps", &ttyn[5], linebaudrate); 67733559Srick else 67833559Srick bpsmsg[0] = '\0'; 67933559Srick if (UsingProtocol != 'g') 68033559Srick sprintf(pmsg, " %c protocol", UsingProtocol); 68133559Srick else 68233559Srick pmsg[0] = '\0'; 68333559Srick if (MaxGrade != '\177') 68433559Srick sprintf(gmsg, " grade %c", MaxGrade); 68533559Srick else 68633559Srick gmsg[0] = '\0'; 68734164Srick sprintf(smsg, "(startup%s%s%s)", bpsmsg, pmsg, gmsg); 68833559Srick logent(smsg, "OK"); 68917767Sralph US_SST(us_s_gress); 69033559Srick StartTime = Now.time; 69113639Ssam systat(Rmtname, SS_INPROGRESS, "TALKING"); 69213639Ssam ret = cntrl(Role, wkpre); 69313639Ssam DEBUG(1, "cntrl - %d\n", ret); 69413639Ssam signal(SIGINT, SIG_IGN); 69513639Ssam signal(SIGHUP, SIG_IGN); 69613639Ssam signal(SIGALRM, timeout); 69734164Srick sprintf(smsg, "(conversation complete %ld sent %ld received)", 69833559Srick Bytes_Sent, Bytes_Received); 69917767Sralph if (ret == SUCCESS) { 70033559Srick logent(smsg, "OK"); 70117767Sralph US_SST(us_s_ok); 70213639Ssam rmstat(Rmtname); 70313639Ssam 70417767Sralph } else { 70533559Srick logent(smsg, _FAILED); 70617767Sralph US_SST(us_s_cf); 70717767Sralph systat(Rmtname, SS_FAIL, "CONVERSATION FAILED"); 70813639Ssam } 70933559Srick alarm(IsTcpIp?MAXMSGTIME*4:MAXMSGTIME); 71013639Ssam DEBUG(4, "send OO %d,", ret); 71113639Ssam if (!setjmp(Sjbuf)) { 71213639Ssam for (;;) { 71313639Ssam omsg('O', "OOOOO", Ofn); 71413639Ssam ret = imsg(msg, Ifn); 71513639Ssam if (ret != 0) 71613639Ssam break; 71713639Ssam if (msg[0] == 'O') 71813639Ssam break; 71913639Ssam } 72013639Ssam } 72113639Ssam alarm(0); 72217767Sralph clsacu(); 72317767Sralph rmlock(CNULL); 72433559Srick 72513639Ssam } 72613639Ssam next: 72713639Ssam if (!onesys) { 72813639Ssam goto loop; 72913639Ssam } 73013639Ssam cleanup(0); 73113639Ssam } 73213639Ssam 73317767Sralph #ifndef USG 73413639Ssam struct sgttyb Hupvec; 73513639Ssam #endif 73613639Ssam 73725703Sbloom /* 73825703Sbloom * cleanup and exit with "code" status 73913639Ssam */ 74013639Ssam cleanup(code) 74113639Ssam register int code; 74213639Ssam { 74313639Ssam signal(SIGINT, SIG_IGN); 74413639Ssam signal(SIGHUP, SIG_IGN); 74513639Ssam rmlock(CNULL); 74625703Sbloom sleep(5); /* Wait for any pending output */ 74713639Ssam clsacu(); 74813639Ssam logcls(); 74913639Ssam if (Role == SLAVE) { 75017767Sralph if (!IsTcpIp) { 75117767Sralph #ifdef USG 75213639Ssam Savettyb.c_cflag |= HUPCL; 75323590Sbloom (void) ioctl(0, TCSETA, &Savettyb); 75417767Sralph #else !USG 75523590Sbloom (void) ioctl(0, TIOCHPCL, STBNULL); 75618616Sralph #ifdef TIOCSDTR 75723590Sbloom (void) ioctl(0, TIOCCDTR, STBNULL); 75818616Sralph sleep(2); 75923590Sbloom (void) ioctl(0, TIOCSDTR, STBNULL); 76018616Sralph #else !TIOCSDTR 76123590Sbloom (void) ioctl(0, TIOCGETP, &Hupvec); 76213639Ssam Hupvec.sg_ispeed = B0; 76313639Ssam Hupvec.sg_ospeed = B0; 76423590Sbloom (void) ioctl(0, TIOCSETP, &Hupvec); 76525703Sbloom #endif !TIOCSDTR 76613639Ssam sleep(2); 76723590Sbloom (void) ioctl(0, TIOCSETP, &Savettyb); 76817767Sralph /* make *sure* exclusive access is off */ 76923590Sbloom (void) ioctl(0, TIOCNXCL, STBNULL); 77017767Sralph #endif !USG 77113639Ssam } 77213639Ssam if (ttyn != NULL) 77313639Ssam chmod(ttyn, 0600); 77413639Ssam } 77513639Ssam if (Ofn != -1) { 77613639Ssam if (Role == MASTER) 77713639Ssam write(Ofn, EOTMSG, strlen(EOTMSG)); 77813639Ssam close(Ifn); 77913639Ssam close(Ofn); 78013639Ssam } 78118616Sralph #ifdef DIALINOUT 78218616Sralph /* reenable logins on dialout */ 78318616Sralph reenable(); 78418616Sralph #endif DIALINOUT 78513639Ssam if (code == 0) 78613639Ssam xuuxqt(); 78717767Sralph else 78817767Sralph DEBUG(1, "exit code %d\n", code); 78925703Sbloom setdebug (DBG_CLEAN); 79033559Srick do_connect_accounting(); 79113639Ssam exit(code); 79213639Ssam } 79313639Ssam 79433559Srick do_connect_accounting() 79533559Srick { 79633945Srick #ifdef DO_CONNECT_ACCOUNTING 79733559Srick register FILE *fp; 79833559Srick struct tm *localtime(); 79933559Srick register struct tm *tm; 80033559Srick int flags; 80133559Srick 80233559Srick if (StartTime == 0) 80333559Srick return; 80433559Srick 80533945Srick fp = fopen(DO_CONNECT_ACCOUNTING, "a"); 80633945Srick if (fp == NULL) { 80733945Srick syslog(LOG_ALERT, "fopen(%s) failed: %m",DO_CONNECT_ACCOUNTING); 80833945Srick cleanup(FAIL); 80933945Srick } 81033559Srick 81133559Srick tm = localtime(&StartTime); 81233559Srick #ifdef F_SETFL 81333559Srick flags = fcntl(fileno(fp), F_GETFL, 0); 81433559Srick fcntl(fileno(fp), F_SETFL, flags|O_APPEND); 81533559Srick #endif 81633559Srick #ifdef USG 81733559Srick fprintf(fp,"%s %d %d%.2d%.2d %.2d%.2d %d %ld %s %ld %ld\n", 81833559Srick #else /* V7 */ 81933559Srick fprintf(fp,"%s %d %d%02d%02d %02d%02d %d %ld %s %ld %ld\n", 82033559Srick #endif /* V7 */ 82133559Srick Rmtname, InitialRole, tm->tm_year, tm->tm_mon + 1, 82233559Srick tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_wday, 82333559Srick (Now.time - StartTime + 59) / 60, 82433559Srick ttyn == NULL ? "ttyp0" : &ttyn[5], 82533559Srick Bytes_Sent, Bytes_Received); 82633559Srick fclose(fp); 82733559Srick #endif /* DO_CONNECT_ACCOUNTING */ 82833559Srick } 82933559Srick 83025703Sbloom /* 83125703Sbloom * on interrupt - remove locks and exit 83213639Ssam */ 83313639Ssam 834*46879Sbostic static void 83513639Ssam onintr(inter) 83613639Ssam register int inter; 83713639Ssam { 83833559Srick char str[BUFSIZ]; 83913639Ssam signal(inter, SIG_IGN); 84034164Srick sprintf(str, "(SIGNAL %d)", inter); 84113639Ssam logent(str, "CAUGHT"); 84217767Sralph US_SST(us_s_intr); 84323590Sbloom if (*Rmtname && strncmp(Rmtname, Myname, MAXBASENAME)) 84417767Sralph systat(Rmtname, SS_FAIL, str); 84534164Srick sprintf(str, "(conversation complete %ld sent %ld received)", 84633559Srick Bytes_Sent, Bytes_Received); 84733559Srick logent(str, _FAILED); 84817767Sralph if (inter == SIGPIPE && !onesys) 84917767Sralph longjmp(Pipebuf, 1); 85013639Ssam cleanup(inter); 85113639Ssam } 85213639Ssam 85313639Ssam /* 85413639Ssam * Catch a special signal 85536449Smarc * (SIGUSR1), and toggle debugging between 0 and 30. 85613639Ssam * Handy for looking in on long running uucicos. 85713639Ssam */ 858*46879Sbostic static void 85925703Sbloom dbg_signal() 86013639Ssam { 86125703Sbloom Debug = (Debug == 0) ? 30 : 0; 86225703Sbloom setdebug(DBG_PERM); 86325703Sbloom if (Debug > 0) 86425703Sbloom logent("Signal Enabled", "DEBUG"); 86525703Sbloom } 86617767Sralph 86725703Sbloom 86825703Sbloom /* 86925703Sbloom * Check debugging requests, and open RMTDEBUG audit file if necessary. If an 87025703Sbloom * audit file is needed, the parm argument indicates how to create the file: 87125703Sbloom * 87225703Sbloom * DBG_TEMP - Open a temporary file, with filename = RMTDEBUG/pid. 87325703Sbloom * DBG_PERM - Open a permanent audit file, filename = RMTDEBUG/Rmtname. 87425703Sbloom * If a temp file already exists, it is mv'ed to be permanent. 87525703Sbloom * DBG_CLEAN - Cleanup; unlink temp files. 87625703Sbloom * 87725703Sbloom * Restrictions - this code can only cope with one open debug file at a time. 87825703Sbloom * Each call creates a new file; if an old one of the same name exists it will 87925703Sbloom * be overwritten. 88025703Sbloom */ 88125703Sbloom setdebug(parm) 88225703Sbloom int parm; 88325703Sbloom { 88425703Sbloom char buf[BUFSIZ]; /* Buffer for building filenames */ 88525703Sbloom static char *temp = NULL; /* Ptr to temporary file name */ 88625703Sbloom static int auditopen = 0; /* Set to 1 when we open a file */ 88725703Sbloom struct stat stbuf; /* File status buffer */ 88825703Sbloom 88925703Sbloom /* 89025703Sbloom * If movement or cleanup of a temp file is indicated, we do it no 89125703Sbloom * matter what. 89225703Sbloom */ 89325703Sbloom if (temp != CNULL && parm == DBG_PERM) { 89425703Sbloom sprintf(buf, "%s/%s", RMTDEBUG, Rmtname); 89525703Sbloom unlink(buf); 89625703Sbloom if (link(temp, buf) != 0) { 89723590Sbloom Debug = 0; 89833945Srick syslog(LOG_ERR, "RMTDEBUG link(%s,%s) failed: %m", 89933945Srick temp, buf); 90033945Srick cleanup(FAIL); 90125703Sbloom } 90225703Sbloom parm = DBG_CLEAN; 90323590Sbloom } 90425703Sbloom if (parm == DBG_CLEAN) { 90525703Sbloom if (temp != CNULL) { 90625703Sbloom unlink(temp); 90725703Sbloom free(temp); 90825703Sbloom temp = CNULL; 90925703Sbloom } 91025703Sbloom return; 91125703Sbloom } 91225703Sbloom 91325703Sbloom if (Debug == 0) 91425703Sbloom return; /* Gotta be in debug to come here. */ 91525703Sbloom 91625703Sbloom /* 91725703Sbloom * If we haven't opened a file already, we can just return if it's 91825703Sbloom * alright to use the stderr we came in with. We can if: 91925703Sbloom * 92025703Sbloom * Role == MASTER, and Stderr is a regular file, a TTY or a pipe. 92125703Sbloom * 92225703Sbloom * Caution: Detecting when stderr is a pipe is tricky, because the 4.2 92325703Sbloom * man page for fstat(2) disagrees with reality, and System V leaves it 92425703Sbloom * undefined, which means different implementations act differently. 92525703Sbloom */ 92625703Sbloom if (!auditopen && Role == MASTER) { 92725703Sbloom if (isatty(fileno(stderr))) 92825703Sbloom return; 92925703Sbloom else if (fstat(fileno(stderr), &stbuf) == 0) { 93025703Sbloom #ifdef USG 93125703Sbloom /* Is Regular File or Fifo */ 93225703Sbloom if ((stbuf.st_mode & 0060000) == 0) 93325703Sbloom return; 93425703Sbloom #else !USG 93517767Sralph #ifdef BSD4_2 93625703Sbloom /* Is Regular File */ 93725703Sbloom if ((stbuf.st_mode & S_IFMT) == S_IFREG || 93825703Sbloom stbuf.st_mode == 0) /* Is a pipe */ 93925703Sbloom return; 94025703Sbloom #else !BSD4_2 94125703Sbloom /* Is Regular File or Pipe */ 94225703Sbloom if ((stbuf.st_mode & S_IFMT) == S_IFREG) 94325703Sbloom return; 94425703Sbloom #endif BSD4_2 94525703Sbloom #endif USG 94625703Sbloom } 94717767Sralph } 94813639Ssam 94925703Sbloom /* 95025703Sbloom * We need RMTDEBUG directory to do auditing. If the file doesn't exist, 95125703Sbloom * then we forget about debugging; if it exists but has improper owner- 95225703Sbloom * ship or modes, we gripe about it in ERRLOG. 95325703Sbloom */ 95425703Sbloom if (stat(RMTDEBUG, &stbuf) != SUCCESS) { 95525703Sbloom Debug = 0; 95625703Sbloom return; 95725703Sbloom } 95825703Sbloom if ((geteuid() != stbuf.st_uid) || /* We must own it */ 95925703Sbloom ((stbuf.st_mode & 0170700) != 040700)) { /* Directory, rwx */ 96025703Sbloom Debug = 0; 96133945Srick syslog(LOG_ERR, "%s: invalid directory mode: %o", RMTDEBUG, 96233945Srick stbuf.st_mode); 96325703Sbloom return; 96425703Sbloom } 96513639Ssam 96625703Sbloom if (parm == DBG_TEMP) { 96725703Sbloom sprintf(buf, "%s/%d", RMTDEBUG, getpid()); 96825703Sbloom temp = malloc(strlen (buf) + 1); 96925703Sbloom if (temp == CNULL) { 97025703Sbloom Debug = 0; 97133945Srick syslog(LOG_ERR, "RMTDEBUG malloc failed: %m"); 97233945Srick cleanup(FAIL); 97325703Sbloom } 97425703Sbloom strcpy(temp, buf); 97525703Sbloom } else 97625703Sbloom sprintf(buf, "%s/%s", RMTDEBUG, Rmtname); 97713639Ssam 97825703Sbloom unlink(buf); 97925703Sbloom if (freopen(buf, "w", stderr) != stderr) { 98025703Sbloom Debug = 0; 98133945Srick syslog(LOG_ERR, "RMTDEBUG freopen(%s) failed: %m", buf); 98233945Srick cleanup(FAIL); 98325703Sbloom } 98425703Sbloom setbuf(stderr, CNULL); 98525703Sbloom auditopen = 1; 98613639Ssam } 98713639Ssam 98823590Sbloom /* 98925703Sbloom * catch SIGALRM routine 99013639Ssam */ 991*46879Sbostic static void 99213639Ssam timeout() 99313639Ssam { 99423590Sbloom extern int HaveSentHup; 99523590Sbloom if (!HaveSentHup) { 99623590Sbloom logent(Rmtname, "TIMEOUT"); 99723590Sbloom if (*Rmtname && strncmp(Rmtname, Myname, MAXBASENAME)) { 99823590Sbloom US_SST(us_s_tmot); 99923590Sbloom systat(Rmtname, SS_FAIL, "TIMEOUT"); 100023590Sbloom } 100117767Sralph } 100213639Ssam longjmp(Sjbuf, 1); 100313639Ssam } 100413639Ssam 100513639Ssam static char * 100613639Ssam pskip(p) 100713639Ssam register char *p; 100813639Ssam { 100917767Sralph while(*p && *p != ' ') 101013639Ssam ++p; 101123590Sbloom while(*p && *p == ' ') 101217767Sralph *p++ = 0; 101317767Sralph return p; 101413639Ssam } 101534164Srick 101634164Srick /* 101734164Srick * clobber argv so ps will show what we're doing. 101834164Srick * stolen from sendmail 101934164Srick */ 102034164Srick /*VARARGS1*/ 102134164Srick setproctitle(fmt, a, b, c) 102234164Srick char *fmt; 102334164Srick { 102434164Srick #ifdef SETPROCTITLE 102534164Srick register char *p; 102634164Srick register int i; 102734164Srick extern char **Argv; 102834164Srick extern char *LastArgv; 102934164Srick char buf[BUFSIZ]; 103034164Srick 103134164Srick (void) sprintf(buf, fmt, a, b, c); 103234164Srick 103334164Srick /* make ps print "(sendmail)" */ 103434164Srick p = Argv[0]; 103534164Srick *p++ = '-'; 103634164Srick 103734164Srick i = strlen(buf); 103834164Srick if (i > LastArgv - p - 2) { 103934164Srick i = LastArgv - p - 2; 104034164Srick buf[i] = '\0'; 104134164Srick } 104234164Srick (void) strcpy(p, buf); 104334164Srick p += i; 104434164Srick while (p < LastArgv) 104534164Srick *p++ = ' '; 104634164Srick #endif SETPROCTITLE 104734164Srick } 1048