113639Ssam #ifndef lint 2*33945Srick static char sccsid[] = "@(#)cico.c 5.16 (Berkeley) 04/05/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 8725703Sbloom /* 8825703Sbloom * this program is used to place a call to a 8913639Ssam * remote machine, login, and copy files between the two machines. 9013639Ssam */ 9113639Ssam main(argc, argv) 9225703Sbloom int argc; 93*33945Srick char **argv; 9413639Ssam { 9513639Ssam register int ret; 9613639Ssam int seq; 9713639Ssam char wkpre[NAMESIZE], file[NAMESIZE]; 9825703Sbloom char msg[MAXFULLNAME], *q; 9913639Ssam register char *p; 10025703Sbloom extern onintr(), timeout(), dbg_signal(); 10113639Ssam extern char *pskip(); 102*33945Srick extern char *optarg; 103*33945Srick extern int optind; 10423725Sbloom char rflags[MAXFULLNAME]; 10523590Sbloom #ifdef NOGETPEER 10617767Sralph u_long Hostnumber = 0; 10723590Sbloom #endif NOGETPEER 10813639Ssam 10913639Ssam strcpy(Progname, "uucico"); 11013639Ssam 11126149Sbloom #ifdef BSD4_2 112*33945Srick sigsetmask(0L); /* in case we inherit blocked signals */ 11326149Sbloom #endif BSD4_2 11413639Ssam signal(SIGINT, onintr); 11513639Ssam signal(SIGHUP, onintr); 11613639Ssam signal(SIGQUIT, onintr); 11713639Ssam signal(SIGTERM, onintr); 11813639Ssam signal(SIGPIPE, onintr); /* 4.1a tcp-ip stupidity */ 11925703Sbloom signal(SIGFPE, dbg_signal); 12013639Ssam ret = guinfo(getuid(), User, msg); 12113639Ssam strcpy(Loginuser, User); 12223590Sbloom uucpname(Myname); 123*33945Srick if (ret == FAIL) { 124*33945Srick syslog(LOG_ERR, "can't get uid"); 125*33945Srick cleanup(FAIL); 126*33945Srick } 12713639Ssam 12825703Sbloom setbuf (stderr, CNULL); 12925703Sbloom 13025703Sbloom rflags[0] = '\0'; 13113639Ssam umask(WFMASK); 13213639Ssam strcpy(Rmtname, Myname); 13313639Ssam Ifn = Ofn = -1; 134*33945Srick while ((ret = getopt(argc, argv, "RLd:g:p:r:s:x:t:")) != EOF) 135*33945Srick switch(ret){ 13613639Ssam case 'd': 137*33945Srick Spool = optarg; 13813639Ssam break; 13913639Ssam case 'g': 14018616Sralph case 'p': 141*33945Srick MaxGrade = DefMaxGrade = *optarg; 14213639Ssam break; 14313639Ssam case 'r': 144*33945Srick Role = atoi(optarg); 14513639Ssam break; 14617767Sralph case 'R': 14717767Sralph ReverseRole++; 14817767Sralph Role = MASTER; 14917767Sralph break; 15013639Ssam case 's': 151*33945Srick strncpy(Rmtname, optarg, MAXBASENAME); 15223590Sbloom Rmtname[MAXBASENAME] = '\0'; 15313639Ssam if (Rmtname[0] != '\0') 15413639Ssam onesys = 1; 15513639Ssam break; 15613639Ssam case 'x': 157*33945Srick Debug = atoi(optarg); 15813639Ssam if (Debug <= 0) 15913639Ssam Debug = 1; 160*33945Srick strcat(rflags, argv[optind-1]); 16113639Ssam break; 16218616Sralph case 't': 163*33945Srick turntime = atoi(optarg)*60;/* minutes to seconds */ 16418616Sralph break; 16517767Sralph case 'L': /* local calls only */ 16617767Sralph LocalOnly++; 16717767Sralph break; 16823590Sbloom #ifdef NOGETPEER 16917767Sralph case 'h': 17017767Sralph Hostnumber = inet_addr(&argv[1][2]); 17117767Sralph break; 17223590Sbloom #endif NOGETPEER 173*33945Srick case '?': 17413639Ssam default: 175*33945Srick fprintf(stderr, "unknown flag %s (ignored)\n", 176*33945Srick argv[optind-1]); 17713639Ssam break; 17813639Ssam } 17913639Ssam 180*33945Srick while (optind < argc) 181*33945Srick fprintf(stderr, "unknown argument %s (ignored)\n", 182*33945Srick argv[optind++]); 18317767Sralph 18427069Sbloom if (Debug && Role == MASTER) 18527069Sbloom chkdebug(); 18627069Sbloom 18725124Sbloom /* Try to run as uucp */ 18817767Sralph setgid(getegid()); 18917767Sralph setuid(geteuid()); 19017767Sralph #ifdef TIOCNOTTY 19117767Sralph /* 19217767Sralph * detach uucico from controlling terminal 19317767Sralph * to defend against rlogind sending us a SIGKILL (!!!) 19417767Sralph */ 19517767Sralph if (Role == MASTER && (ret = open("/dev/tty", 2)) >= 0) { 19617767Sralph ioctl(ret, TIOCNOTTY, STBNULL); 19717767Sralph close(ret); 19817767Sralph } 19917767Sralph #endif TIOCNOTTY 20017767Sralph #ifdef BSD4_2 20125517Stef if (getpgrp(0) == 0) { /* We have no controlling terminal */ 20217767Sralph setpgrp(0, getpid()); 20317767Sralph } 204*33945Srick #ifdef USE_SYSLOG 205*33945Srick #ifdef BSD4_3 206*33945Srick openlog("uucico", LOG_PID, LOG_UUCP); 207*33945Srick #else /* !BSD4_3 */ 208*33945Srick openlog("uucico", LOG_PID); 209*33945Srick #endif /* !BSD4_3 */ 210*33945Srick #endif /* USE_SYSLOG */ 21117767Sralph #endif BSD4_2 21217767Sralph 213*33945Srick #ifdef BSD4_3 214*33945Srick unsetenv("TZ"); /* We don't want him resetting our time zone */ 215*33945Srick #endif /* !BSD4_3 */ 216*33945Srick 217*33945Srick if (subchdir(Spool) < 0) { 218*33945Srick syslog(LOG_ERR, "chdir(%s) failed: %m", Spool); 219*33945Srick cleanup(FAIL); 220*33945Srick } 221*33945Srick 22213639Ssam strcpy(Wrkdir, Spool); 22313639Ssam 22425703Sbloom if (Debug) { 22525703Sbloom setdebug ((Role == SLAVE) ? DBG_TEMP : DBG_PERM); 22625703Sbloom if (Debug > 0) 22725703Sbloom logent ("Local Enabled", "DEBUG"); 22825703Sbloom } 22925703Sbloom 23025703Sbloom /* 23125703Sbloom * First time through: If we're the slave, do initial checking. 23225703Sbloom */ 23313639Ssam if (Role == SLAVE) { 23417767Sralph /* check for /etc/nologin */ 23525124Sbloom if (access(NOLOGIN, 0) == 0) { 23617767Sralph logent(NOLOGIN, "UUCICO SHUTDOWN"); 23723590Sbloom if (Debug > 4) 23817767Sralph logent("DEBUGGING", "continuing anyway"); 23917767Sralph else 24017767Sralph cleanup(1); 24117767Sralph } 24225703Sbloom Ifn = 0; 24325703Sbloom Ofn = 1; 24417767Sralph #ifdef TCPIP 24517767Sralph /* 24617767Sralph * Determine if we are on TCPIP 24717767Sralph */ 24833559Srick if (isatty(Ifn) == 0) { 24917767Sralph IsTcpIp = 1; 25017767Sralph DEBUG(4, "TCPIP connection -- ioctl-s disabled\n", CNULL); 25123590Sbloom } else 25223590Sbloom IsTcpIp = 0; 25317767Sralph #endif TCPIP 25413639Ssam /* initial handshake */ 25513639Ssam onesys = 1; 25617767Sralph if (!IsTcpIp) { 25717767Sralph #ifdef USG 25825703Sbloom ret = ioctl(Ifn, TCGETA, &Savettyb); 25913639Ssam Savettyb.c_cflag = (Savettyb.c_cflag & ~CS8) | CS7; 26013639Ssam Savettyb.c_oflag |= OPOST; 26113639Ssam Savettyb.c_lflag |= (ISIG|ICANON|ECHO); 26217767Sralph #else !USG 26325703Sbloom ret = ioctl(Ifn, TIOCGETP, &Savettyb); 26413639Ssam Savettyb.sg_flags |= ECHO; 26513639Ssam Savettyb.sg_flags &= ~RAW; 26617767Sralph #endif !USG 26725703Sbloom ttyn = ttyname(Ifn); 26813639Ssam } 26913639Ssam fixmode(Ifn); 27025703Sbloom 27125703Sbloom /* 27225703Sbloom * Initial Message -- tell them we're here, and who we are. 27325703Sbloom */ 27418616Sralph sprintf(msg, "here=%s", Myfullname); 27517767Sralph omsg('S', msg, Ofn); 27613639Ssam signal(SIGALRM, timeout); 27733559Srick alarm(IsTcpIp?MAXMSGTIME*4:MAXMSGTIME); 27813639Ssam if (setjmp(Sjbuf)) { 27913639Ssam /* timed out */ 28017767Sralph if (!IsTcpIp) { 28117767Sralph #ifdef USG 28225703Sbloom ret = ioctl(Ifn, TCSETA, &Savettyb); 28325703Sbloom 28423590Sbloom #else !USG 28525703Sbloom ret = ioctl(Ifn, TIOCSETP, &Savettyb); 28623590Sbloom #endif !USG 28713639Ssam } 28817767Sralph cleanup(0); 28913639Ssam } 29013639Ssam for (;;) { 29113639Ssam ret = imsg(msg, Ifn); 29225703Sbloom if (ret != SUCCESS) { 29313639Ssam alarm(0); 29417767Sralph if (!IsTcpIp) { 29517767Sralph #ifdef USG 29625703Sbloom ret = ioctl(Ifn, TCSETA, &Savettyb); 29723590Sbloom #else !USG 29825703Sbloom ret = ioctl(Ifn, TIOCSETP, &Savettyb); 29923590Sbloom #endif !USG 30013639Ssam } 30117767Sralph cleanup(0); 30213639Ssam } 30313639Ssam if (msg[0] == 'S') 30413639Ssam break; 30513639Ssam } 30613639Ssam alarm(0); 30713639Ssam q = &msg[1]; 30813639Ssam p = pskip(q); 30923590Sbloom strncpy(Rmtname, q, MAXBASENAME); 31023590Sbloom Rmtname[MAXBASENAME] = '\0'; 31125703Sbloom 31225703Sbloom /* 31325703Sbloom * Now that we know who they are, give the audit file the right 31425703Sbloom * name. 31525703Sbloom */ 31625703Sbloom setdebug (DBG_PERM); 31713639Ssam DEBUG(4, "sys-%s\n", Rmtname); 31823725Sbloom /* The versys will also do an alias on the incoming name */ 31923725Sbloom if (versys(&Rmtname)) { 32033559Srick #ifdef NOSTRANGERS 32123725Sbloom /* If we don't know them, we won't talk to them... */ 322*33945Srick syslog(LOG_WARNING, "Unknown host: %s", Rmtname); 32323590Sbloom omsg('R', "You are unknown to me", Ofn); 32423590Sbloom cleanup(0); 32523725Sbloom #endif NOSTRANGERS 32623590Sbloom } 32717767Sralph #ifdef BSDTCP 32817767Sralph /* we must make sure they are really who they say they 32917767Sralph * are. We compare the hostnumber with the number in the hosts 33017767Sralph * table for the site they claim to be. 33117767Sralph */ 33217767Sralph if (IsTcpIp) { 33317767Sralph struct hostent *hp; 33417767Sralph char *cpnt, *inet_ntoa(); 33525703Sbloom int fromlen; 33617767Sralph struct sockaddr_in from; 33725124Sbloom extern char PhoneNumber[]; 33817767Sralph 33923590Sbloom #ifdef NOGETPEER 34023590Sbloom from.sin_addr.s_addr = Hostnumber; 34123590Sbloom from.sin_family = AF_INET; 34223590Sbloom #else !NOGETPEER 34325703Sbloom fromlen = sizeof(from); 34425703Sbloom if (getpeername(Ifn, &from, &fromlen) < 0) { 34517767Sralph logent(Rmtname, "NOT A TCP CONNECTION"); 34617767Sralph omsg('R', "NOT TCP", Ofn); 34717767Sralph cleanup(0); 34817767Sralph } 34923590Sbloom #endif !NOGETPEER 35017767Sralph hp = gethostbyaddr(&from.sin_addr, 35117767Sralph sizeof (struct in_addr), from.sin_family); 35225703Sbloom if (hp == NULL) { 35317767Sralph /* security break or just old host table? */ 35417767Sralph logent(Rmtname, "UNKNOWN IP-HOST Name ="); 35517767Sralph cpnt = inet_ntoa(from.sin_addr), 35617767Sralph logent(cpnt, "UNKNOWN IP-HOST Number ="); 35717767Sralph sprintf(wkpre, "%s/%s isn't in my host table", 35817767Sralph Rmtname, cpnt); 35917767Sralph omsg('R' ,wkpre ,Ofn); 36017767Sralph cleanup(0); 36117767Sralph } 36225703Sbloom if (Debug > 99) 36317767Sralph logent(Rmtname,"Request from IP-Host name ="); 36425124Sbloom /* 36525124Sbloom * The following is to determine if the name given us by 36625124Sbloom * the Remote uucico matches any of the names 36717767Sralph * given its network number (remote machine) in our 36817767Sralph * host table. 36925124Sbloom * We could check the aliases, but that won't work in 37025124Sbloom * all cases (like if you are running the domain 37125124Sbloom * server, where you don't get any aliases). The only 37225124Sbloom * reliable way I can think of that works in ALL cases 37325124Sbloom * is too look up the site in L.sys and see if the 37425124Sbloom * sitename matches what we would call him if we 37525124Sbloom * originated the call. 37617767Sralph */ 37725124Sbloom /* PhoneNumber contains the official network name of the host we are checking. (set in versys.c) */ 37825124Sbloom if (sncncmp(PhoneNumber, hp->h_name, SYSNSIZE) == 0) { 37917767Sralph if (Debug > 99) 38017767Sralph logent(q,"Found in host Tables"); 38125124Sbloom } else { 38225124Sbloom logent(hp->h_name, "FORGED HOSTNAME"); 38325124Sbloom logent(inet_ntoa(from.sin_addr), "ORIGINATED AT"); 38425124Sbloom logent(PhoneNumber, "SHOULD BE"); 38525124Sbloom sprintf(wkpre, "You're not who you claim to be: %s != %s", hp->h_name, PhoneNumber); 38625124Sbloom omsg('R', wkpre, Ofn); 38725124Sbloom cleanup(0); 38817767Sralph } 38917767Sralph } 39017767Sralph #endif BSDTCP 39117767Sralph 39225703Sbloom if (mlock(Rmtname)) { 39313639Ssam omsg('R', "LCK", Ofn); 39413639Ssam cleanup(0); 39513639Ssam } 39613639Ssam else if (callback(Loginuser)) { 39713639Ssam signal(SIGINT, SIG_IGN); 39813639Ssam signal(SIGHUP, SIG_IGN); 39913639Ssam omsg('R', "CB", Ofn); 40013639Ssam logent("CALLBACK", "REQUIRED"); 40113639Ssam /* set up for call back */ 40217767Sralph systat(Rmtname, SS_CALLBACK, "CALLING BACK"); 40313639Ssam gename(CMDPRE, Rmtname, 'C', file); 40413639Ssam close(creat(subfile(file), 0666)); 40513639Ssam xuucico(Rmtname); 40613639Ssam cleanup(0); 40713639Ssam } 40813639Ssam seq = 0; 40913639Ssam while (*p == '-') { 41013639Ssam q = pskip(p); 41113639Ssam switch(*(++p)) { 41213639Ssam case 'x': 41325703Sbloom if (Debug == 0) { 41425703Sbloom Debug = atoi(++p); 41525703Sbloom if (Debug <= 0) 41625703Sbloom Debug = 1; 41725703Sbloom setdebug(DBG_PERM); 41825703Sbloom if (Debug > 0) 41925703Sbloom logent("Remote Enabled", "DEBUG"); 42025703Sbloom } else { 42125703Sbloom DEBUG(1, "Remote debug request ignored\n", 42225703Sbloom CNULL); 42325703Sbloom } 42413639Ssam break; 42513639Ssam case 'Q': 42613639Ssam seq = atoi(++p); 42713639Ssam break; 42818616Sralph case 'p': 42918616Sralph MaxGrade = DefMaxGrade = *++p; 43018616Sralph DEBUG(4, "MaxGrade set to %c\n", MaxGrade); 43118616Sralph break; 43223590Sbloom case 'v': 43323590Sbloom if (strncmp(p, "grade", 5) == 0) { 43423590Sbloom p += 6; 43523590Sbloom MaxGrade = DefMaxGrade = *p++; 43623590Sbloom DEBUG(4, "MaxGrade set to %c\n", MaxGrade); 43723590Sbloom } 43823590Sbloom break; 43913639Ssam default: 44013639Ssam break; 44113639Ssam } 44213639Ssam p = q; 44313639Ssam } 44413639Ssam if (callok(Rmtname) == SS_BADSEQ) { 44513639Ssam logent("BADSEQ", "PREVIOUS"); 44613639Ssam omsg('R', "BADSEQ", Ofn); 44713639Ssam cleanup(0); 44813639Ssam } 44917767Sralph #ifdef GNXSEQ 45013639Ssam if ((ret = gnxseq(Rmtname)) == seq) { 45113639Ssam omsg('R', "OK", Ofn); 45213639Ssam cmtseq(); 45317767Sralph } else { 45417767Sralph #else !GNXSEQ 45517767Sralph if (seq == 0) 45617767Sralph omsg('R', "OK", Ofn); 45713639Ssam else { 45817767Sralph #endif !GNXSEQ 45913639Ssam systat(Rmtname, Stattype[7], Stattext[7]); 46023590Sbloom logent("BAD SEQ", "FAILED HANDSHAKE"); 46117767Sralph #ifdef GNXSEQ 46213639Ssam ulkseq(); 46317767Sralph #endif GNXSEQ 46413639Ssam omsg('R', "BADSEQ", Ofn); 46513639Ssam cleanup(0); 46613639Ssam } 46713639Ssam if (ttyn != NULL) 46813639Ssam chmod(ttyn, 0600); 46913639Ssam } 47017767Sralph 47113639Ssam loop: 47217767Sralph if(setjmp(Pipebuf)) { /* come here on SIGPIPE */ 47317767Sralph clsacu(); 47417767Sralph close(Ofn); 47517767Sralph close(Ifn); 47617767Sralph Ifn = Ofn = -1; 47717767Sralph rmlock(CNULL); 47817767Sralph sleep(3); 47917767Sralph } 48013639Ssam if (!onesys) { 48133559Srick do_connect_accounting(); 482*33945Srick #ifdef DIALINOUT 483*33945Srick /* reenable logins on dialout */ 484*33945Srick reenable(); 485*33945Srick #endif DIALINOUT 48633559Srick StartTime = 0; 48713639Ssam ret = gnsys(Rmtname, Spool, CMDPRE); 48825703Sbloom setdebug(DBG_PERM); 48913639Ssam if (ret == FAIL) 49013639Ssam cleanup(100); 49133559Srick else if (ret == SUCCESS) 49213639Ssam cleanup(0); 49317767Sralph } else if (Role == MASTER && callok(Rmtname) != 0) { 49413639Ssam logent("SYSTEM STATUS", "CAN NOT CALL"); 49513639Ssam cleanup(0); 49613639Ssam } 49713639Ssam 49823590Sbloom sprintf(wkpre, "%c.%.*s", CMDPRE, SYSNSIZE, Rmtname); 49933559Srick StartTime = 0; 50033559Srick Bytes_Sent = Bytes_Received = 0L; 50113639Ssam 50217767Sralph signal(SIGINT, SIG_IGN); 50317767Sralph signal(SIGQUIT, SIG_IGN); 50413639Ssam if (Role == MASTER) { 50533559Srick extern char LineType[]; 50617767Sralph /* check for /etc/nologin */ 50725124Sbloom if (access(NOLOGIN, 0) == 0) { 50817767Sralph logent(NOLOGIN, "UUCICO SHUTDOWN"); 50923590Sbloom if (Debug > 4) 51017767Sralph logent("DEBUGGING", "continuing anyway"); 51117767Sralph else 51217767Sralph cleanup(1); 51317767Sralph } 51413639Ssam /* master part */ 51513639Ssam signal(SIGHUP, SIG_IGN); 51613639Ssam if (Ifn != -1 && Role == MASTER) { 51713639Ssam write(Ofn, EOTMSG, strlen(EOTMSG)); 51813639Ssam clsacu(); 51913639Ssam close(Ofn); 52013639Ssam close(Ifn); 52113639Ssam Ifn = Ofn = -1; 52213639Ssam rmlock(CNULL); 52313639Ssam sleep(3); 52413639Ssam } 52525124Sbloom if (mlock(Rmtname) != SUCCESS) { 52633559Srick DEBUG(1, "LOCKED: call to %s\n", Rmtname); 52717767Sralph US_SST(us_s_lock); 52813639Ssam goto next; 52913639Ssam } 53013639Ssam Ofn = Ifn = conn(Rmtname); 53133559Srick sprintf(msg, "call to %s via %s", Rmtname, LineType); 53213639Ssam if (Ofn < 0) { 53317767Sralph if (Ofn != CF_TIME) 53417767Sralph logent(msg, _FAILED); 53517767Sralph /* avoid excessive 'wrong time' info */ 53623590Sbloom if (Stattype[-Ofn] != SS_WRONGTIME){ 53717767Sralph systat(Rmtname, Stattype[-Ofn], Stattext[-Ofn]); 53817767Sralph US_SST(-Ofn); 53917767Sralph UB_SST(-Ofn); 54017767Sralph } 54113639Ssam goto next; 54217767Sralph } else { 54313639Ssam logent(msg, "SUCCEEDED"); 54417767Sralph US_SST(us_s_cok); 54517767Sralph UB_SST(ub_ok); 54613639Ssam } 54733559Srick InitialRole = MASTER; 54817767Sralph #ifdef TCPIP 54917767Sralph /* 55017767Sralph * Determine if we are on TCPIP 55117767Sralph */ 55225703Sbloom if (isatty(Ifn) == 0) { 55317767Sralph IsTcpIp = 1; 55417767Sralph DEBUG(4, "TCPIP connection -- ioctl-s disabled\n", CNULL); 55523590Sbloom } else 55623590Sbloom IsTcpIp = 0; 55717767Sralph #endif 55817767Sralph 55913639Ssam if (setjmp(Sjbuf)) 56013639Ssam goto next; 56113639Ssam signal(SIGALRM, timeout); 56233559Srick alarm(IsTcpIp?MAXMSGTIME*4:MAXMSGTIME*2); 56313639Ssam for (;;) { 56413639Ssam ret = imsg(msg, Ifn); 56533559Srick if (ret != SUCCESS) { 56613639Ssam alarm(0); 56733559Srick DEBUG(4,"\nimsg failed: errno %d\n", errno); 56817767Sralph logent("imsg 1", _FAILED); 56917767Sralph goto Failure; 57013639Ssam } 57113639Ssam if (msg[0] == 'S') 57213639Ssam break; 57313639Ssam } 57433559Srick alarm(IsTcpIp?MAXMSGTIME*4:MAXMSGTIME); 57517767Sralph #ifdef GNXSEQ 57613639Ssam seq = gnxseq(Rmtname); 57717767Sralph #else !GNXSEQ 57817767Sralph seq = 0; 57917767Sralph #endif !GNXSEQ 58018616Sralph if (MaxGrade != '\177') { 58123590Sbloom DEBUG(2, "Max Grade this transfer is %c\n", MaxGrade); 58225963Sbloom sprintf(msg, "%s -Q%d -p%c -vgrade=%c %s", 58325963Sbloom Myname, seq, MaxGrade, MaxGrade, rflags); 58425963Sbloom } else 58525963Sbloom sprintf(msg, "%s -Q%d %s", Myname, seq, rflags); 58613639Ssam omsg('S', msg, Ofn); 58713639Ssam for (;;) { 58813639Ssam ret = imsg(msg, Ifn); 58913639Ssam DEBUG(4, "msg-%s\n", msg); 59017767Sralph if (ret != SUCCESS) { 59113639Ssam alarm(0); 59217767Sralph #ifdef GNXSEQ 59313639Ssam ulkseq(); 59417767Sralph #endif GNXSEQ 59517767Sralph logent("imsg 2", _FAILED); 59617767Sralph goto Failure; 59713639Ssam } 59813639Ssam if (msg[0] == 'R') 59913639Ssam break; 60013639Ssam } 60113639Ssam alarm(0); 60213639Ssam if (msg[1] == 'B') { 60313639Ssam /* bad sequence */ 60423590Sbloom logent("BAD SEQ", "FAILED HANDSHAKE"); 60517767Sralph US_SST(us_s_hand); 60617767Sralph systat(Rmtname, SS_BADSEQ, Stattext[SS_BADSEQ]); 60717767Sralph #ifdef GNXSEQ 60813639Ssam ulkseq(); 60917767Sralph #endif GNXSEQ 61013639Ssam goto next; 61113639Ssam } 61213639Ssam if (strcmp(&msg[1], "OK") != SAME) { 61323590Sbloom logent(&msg[1], "FAILED HANDSHAKE"); 61417767Sralph US_SST(us_s_hand); 61517767Sralph #ifdef GNXSEQ 61613639Ssam ulkseq(); 61717767Sralph #endif GNXSEQ 61817767Sralph systat(Rmtname, SS_INPROGRESS, 61917767Sralph strcmp(&msg[1], "CB") == SAME? 62023590Sbloom "AWAITING CALLBACK": "FAILED HANDSHAKE"); 62113639Ssam goto next; 62213639Ssam } 62317767Sralph #ifdef GNXSEQ 62413639Ssam cmtseq(); 62517767Sralph #endif GNXSEQ 62613639Ssam } 62717767Sralph DEBUG(1, "Rmtname %s, ", Rmtname); 62813639Ssam DEBUG(1, "Role %s, ", Role ? "MASTER" : "SLAVE"); 62913639Ssam DEBUG(1, "Ifn - %d, ", Ifn); 63013639Ssam DEBUG(1, "Loginuser - %s\n", Loginuser); 63113639Ssam 63225703Sbloom ttyn = ttyname(Ifn); 63325703Sbloom 63433559Srick alarm(IsTcpIp?MAXMSGTIME*4:MAXMSGTIME); 63518616Sralph if (ret=setjmp(Sjbuf)) 63613639Ssam goto Failure; 63713639Ssam ret = startup(Role); 63813639Ssam alarm(0); 63913639Ssam if (ret != SUCCESS) { 64017767Sralph logent("startup", _FAILED); 64113639Ssam Failure: 64217767Sralph US_SST(us_s_start); 64318616Sralph systat(Rmtname, SS_FAIL, ret > 0 ? "CONVERSATION FAILED" : 64418616Sralph "STARTUP FAILED"); 64513639Ssam goto next; 64617767Sralph } else { 64733559Srick char smsg[BUFSIZ], gmsg[10], pmsg[20], bpsmsg[20]; 64833559Srick extern char UsingProtocol; 64933559Srick extern int linebaudrate; 65033559Srick if (ttyn != NULL) 65133559Srick sprintf(bpsmsg, " %s %d bps", &ttyn[5], linebaudrate); 65233559Srick else 65333559Srick bpsmsg[0] = '\0'; 65433559Srick if (UsingProtocol != 'g') 65533559Srick sprintf(pmsg, " %c protocol", UsingProtocol); 65633559Srick else 65733559Srick pmsg[0] = '\0'; 65833559Srick if (MaxGrade != '\177') 65933559Srick sprintf(gmsg, " grade %c", MaxGrade); 66033559Srick else 66133559Srick gmsg[0] = '\0'; 66233559Srick sprintf(smsg, "startup%s%s%s", bpsmsg, pmsg, gmsg); 66333559Srick logent(smsg, "OK"); 66417767Sralph US_SST(us_s_gress); 66533559Srick StartTime = Now.time; 66613639Ssam systat(Rmtname, SS_INPROGRESS, "TALKING"); 66713639Ssam ret = cntrl(Role, wkpre); 66813639Ssam DEBUG(1, "cntrl - %d\n", ret); 66913639Ssam signal(SIGINT, SIG_IGN); 67013639Ssam signal(SIGHUP, SIG_IGN); 67113639Ssam signal(SIGALRM, timeout); 67233559Srick sprintf(smsg, "conversation complete %ld sent %ld received", 67333559Srick Bytes_Sent, Bytes_Received); 67417767Sralph if (ret == SUCCESS) { 67533559Srick logent(smsg, "OK"); 67617767Sralph US_SST(us_s_ok); 67713639Ssam rmstat(Rmtname); 67813639Ssam 67917767Sralph } else { 68033559Srick logent(smsg, _FAILED); 68117767Sralph US_SST(us_s_cf); 68217767Sralph systat(Rmtname, SS_FAIL, "CONVERSATION FAILED"); 68313639Ssam } 68433559Srick alarm(IsTcpIp?MAXMSGTIME*4:MAXMSGTIME); 68513639Ssam DEBUG(4, "send OO %d,", ret); 68613639Ssam if (!setjmp(Sjbuf)) { 68713639Ssam for (;;) { 68813639Ssam omsg('O', "OOOOO", Ofn); 68913639Ssam ret = imsg(msg, Ifn); 69013639Ssam if (ret != 0) 69113639Ssam break; 69213639Ssam if (msg[0] == 'O') 69313639Ssam break; 69413639Ssam } 69513639Ssam } 69613639Ssam alarm(0); 69717767Sralph clsacu(); 69817767Sralph rmlock(CNULL); 69933559Srick 70013639Ssam } 70113639Ssam next: 70213639Ssam if (!onesys) { 70313639Ssam goto loop; 70413639Ssam } 70513639Ssam cleanup(0); 70613639Ssam } 70713639Ssam 70817767Sralph #ifndef USG 70913639Ssam struct sgttyb Hupvec; 71013639Ssam #endif 71113639Ssam 71225703Sbloom /* 71325703Sbloom * cleanup and exit with "code" status 71413639Ssam */ 71513639Ssam cleanup(code) 71613639Ssam register int code; 71713639Ssam { 71813639Ssam signal(SIGINT, SIG_IGN); 71913639Ssam signal(SIGHUP, SIG_IGN); 72013639Ssam rmlock(CNULL); 72125703Sbloom sleep(5); /* Wait for any pending output */ 72213639Ssam clsacu(); 72313639Ssam logcls(); 72413639Ssam if (Role == SLAVE) { 72517767Sralph if (!IsTcpIp) { 72617767Sralph #ifdef USG 72713639Ssam Savettyb.c_cflag |= HUPCL; 72823590Sbloom (void) ioctl(0, TCSETA, &Savettyb); 72917767Sralph #else !USG 73023590Sbloom (void) ioctl(0, TIOCHPCL, STBNULL); 73118616Sralph #ifdef TIOCSDTR 73223590Sbloom (void) ioctl(0, TIOCCDTR, STBNULL); 73318616Sralph sleep(2); 73423590Sbloom (void) ioctl(0, TIOCSDTR, STBNULL); 73518616Sralph #else !TIOCSDTR 73623590Sbloom (void) ioctl(0, TIOCGETP, &Hupvec); 73713639Ssam Hupvec.sg_ispeed = B0; 73813639Ssam Hupvec.sg_ospeed = B0; 73923590Sbloom (void) ioctl(0, TIOCSETP, &Hupvec); 74025703Sbloom #endif !TIOCSDTR 74113639Ssam sleep(2); 74223590Sbloom (void) ioctl(0, TIOCSETP, &Savettyb); 74317767Sralph /* make *sure* exclusive access is off */ 74423590Sbloom (void) ioctl(0, TIOCNXCL, STBNULL); 74517767Sralph #endif !USG 74613639Ssam } 74713639Ssam if (ttyn != NULL) 74813639Ssam chmod(ttyn, 0600); 74913639Ssam } 75013639Ssam if (Ofn != -1) { 75113639Ssam if (Role == MASTER) 75213639Ssam write(Ofn, EOTMSG, strlen(EOTMSG)); 75313639Ssam close(Ifn); 75413639Ssam close(Ofn); 75513639Ssam } 75618616Sralph #ifdef DIALINOUT 75718616Sralph /* reenable logins on dialout */ 75818616Sralph reenable(); 75918616Sralph #endif DIALINOUT 76013639Ssam if (code == 0) 76113639Ssam xuuxqt(); 76217767Sralph else 76317767Sralph DEBUG(1, "exit code %d\n", code); 76425703Sbloom setdebug (DBG_CLEAN); 76533559Srick do_connect_accounting(); 76613639Ssam exit(code); 76713639Ssam } 76813639Ssam 76933559Srick do_connect_accounting() 77033559Srick { 771*33945Srick #ifdef DO_CONNECT_ACCOUNTING 77233559Srick register FILE *fp; 77333559Srick struct tm *localtime(); 77433559Srick register struct tm *tm; 77533559Srick int flags; 77633559Srick 77733559Srick if (StartTime == 0) 77833559Srick return; 77933559Srick 780*33945Srick fp = fopen(DO_CONNECT_ACCOUNTING, "a"); 781*33945Srick if (fp == NULL) { 782*33945Srick syslog(LOG_ALERT, "fopen(%s) failed: %m",DO_CONNECT_ACCOUNTING); 783*33945Srick cleanup(FAIL); 784*33945Srick } 78533559Srick 78633559Srick tm = localtime(&StartTime); 78733559Srick #ifdef F_SETFL 78833559Srick flags = fcntl(fileno(fp), F_GETFL, 0); 78933559Srick fcntl(fileno(fp), F_SETFL, flags|O_APPEND); 79033559Srick #endif 79133559Srick #ifdef USG 79233559Srick fprintf(fp,"%s %d %d%.2d%.2d %.2d%.2d %d %ld %s %ld %ld\n", 79333559Srick #else /* V7 */ 79433559Srick fprintf(fp,"%s %d %d%02d%02d %02d%02d %d %ld %s %ld %ld\n", 79533559Srick #endif /* V7 */ 79633559Srick Rmtname, InitialRole, tm->tm_year, tm->tm_mon + 1, 79733559Srick tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_wday, 79833559Srick (Now.time - StartTime + 59) / 60, 79933559Srick ttyn == NULL ? "ttyp0" : &ttyn[5], 80033559Srick Bytes_Sent, Bytes_Received); 80133559Srick fclose(fp); 80233559Srick #endif /* DO_CONNECT_ACCOUNTING */ 80333559Srick } 80433559Srick 80525703Sbloom /* 80625703Sbloom * on interrupt - remove locks and exit 80713639Ssam */ 80813639Ssam 80913639Ssam onintr(inter) 81013639Ssam register int inter; 81113639Ssam { 81233559Srick char str[BUFSIZ]; 81313639Ssam signal(inter, SIG_IGN); 81413639Ssam sprintf(str, "SIGNAL %d", inter); 81513639Ssam logent(str, "CAUGHT"); 81617767Sralph US_SST(us_s_intr); 81723590Sbloom if (*Rmtname && strncmp(Rmtname, Myname, MAXBASENAME)) 81817767Sralph systat(Rmtname, SS_FAIL, str); 81933559Srick sprintf(str, "conversation complete %ld sent %ld received", 82033559Srick Bytes_Sent, Bytes_Received); 82133559Srick logent(str, _FAILED); 82217767Sralph if (inter == SIGPIPE && !onesys) 82317767Sralph longjmp(Pipebuf, 1); 82413639Ssam cleanup(inter); 82513639Ssam } 82613639Ssam 82713639Ssam /* 82813639Ssam * Catch a special signal 82913639Ssam * (SIGFPE, ugh), and toggle debugging between 0 and 30. 83013639Ssam * Handy for looking in on long running uucicos. 83113639Ssam */ 83225703Sbloom dbg_signal() 83313639Ssam { 83425703Sbloom Debug = (Debug == 0) ? 30 : 0; 83525703Sbloom setdebug(DBG_PERM); 83625703Sbloom if (Debug > 0) 83725703Sbloom logent("Signal Enabled", "DEBUG"); 83825703Sbloom } 83917767Sralph 84025703Sbloom 84125703Sbloom /* 84225703Sbloom * Check debugging requests, and open RMTDEBUG audit file if necessary. If an 84325703Sbloom * audit file is needed, the parm argument indicates how to create the file: 84425703Sbloom * 84525703Sbloom * DBG_TEMP - Open a temporary file, with filename = RMTDEBUG/pid. 84625703Sbloom * DBG_PERM - Open a permanent audit file, filename = RMTDEBUG/Rmtname. 84725703Sbloom * If a temp file already exists, it is mv'ed to be permanent. 84825703Sbloom * DBG_CLEAN - Cleanup; unlink temp files. 84925703Sbloom * 85025703Sbloom * Restrictions - this code can only cope with one open debug file at a time. 85125703Sbloom * Each call creates a new file; if an old one of the same name exists it will 85225703Sbloom * be overwritten. 85325703Sbloom */ 85425703Sbloom setdebug(parm) 85525703Sbloom int parm; 85625703Sbloom { 85725703Sbloom char buf[BUFSIZ]; /* Buffer for building filenames */ 85825703Sbloom static char *temp = NULL; /* Ptr to temporary file name */ 85925703Sbloom static int auditopen = 0; /* Set to 1 when we open a file */ 86025703Sbloom struct stat stbuf; /* File status buffer */ 86125703Sbloom 86225703Sbloom /* 86325703Sbloom * If movement or cleanup of a temp file is indicated, we do it no 86425703Sbloom * matter what. 86525703Sbloom */ 86625703Sbloom if (temp != CNULL && parm == DBG_PERM) { 86725703Sbloom sprintf(buf, "%s/%s", RMTDEBUG, Rmtname); 86825703Sbloom unlink(buf); 86925703Sbloom if (link(temp, buf) != 0) { 87023590Sbloom Debug = 0; 871*33945Srick syslog(LOG_ERR, "RMTDEBUG link(%s,%s) failed: %m", 872*33945Srick temp, buf); 873*33945Srick cleanup(FAIL); 87425703Sbloom } 87525703Sbloom parm = DBG_CLEAN; 87623590Sbloom } 87725703Sbloom if (parm == DBG_CLEAN) { 87825703Sbloom if (temp != CNULL) { 87925703Sbloom unlink(temp); 88025703Sbloom free(temp); 88125703Sbloom temp = CNULL; 88225703Sbloom } 88325703Sbloom return; 88425703Sbloom } 88525703Sbloom 88625703Sbloom if (Debug == 0) 88725703Sbloom return; /* Gotta be in debug to come here. */ 88825703Sbloom 88925703Sbloom /* 89025703Sbloom * If we haven't opened a file already, we can just return if it's 89125703Sbloom * alright to use the stderr we came in with. We can if: 89225703Sbloom * 89325703Sbloom * Role == MASTER, and Stderr is a regular file, a TTY or a pipe. 89425703Sbloom * 89525703Sbloom * Caution: Detecting when stderr is a pipe is tricky, because the 4.2 89625703Sbloom * man page for fstat(2) disagrees with reality, and System V leaves it 89725703Sbloom * undefined, which means different implementations act differently. 89825703Sbloom */ 89925703Sbloom if (!auditopen && Role == MASTER) { 90025703Sbloom if (isatty(fileno(stderr))) 90125703Sbloom return; 90225703Sbloom else if (fstat(fileno(stderr), &stbuf) == 0) { 90325703Sbloom #ifdef USG 90425703Sbloom /* Is Regular File or Fifo */ 90525703Sbloom if ((stbuf.st_mode & 0060000) == 0) 90625703Sbloom return; 90725703Sbloom #else !USG 90817767Sralph #ifdef BSD4_2 90925703Sbloom /* Is Regular File */ 91025703Sbloom if ((stbuf.st_mode & S_IFMT) == S_IFREG || 91125703Sbloom stbuf.st_mode == 0) /* Is a pipe */ 91225703Sbloom return; 91325703Sbloom #else !BSD4_2 91425703Sbloom /* Is Regular File or Pipe */ 91525703Sbloom if ((stbuf.st_mode & S_IFMT) == S_IFREG) 91625703Sbloom return; 91725703Sbloom #endif BSD4_2 91825703Sbloom #endif USG 91925703Sbloom } 92017767Sralph } 92113639Ssam 92225703Sbloom /* 92325703Sbloom * We need RMTDEBUG directory to do auditing. If the file doesn't exist, 92425703Sbloom * then we forget about debugging; if it exists but has improper owner- 92525703Sbloom * ship or modes, we gripe about it in ERRLOG. 92625703Sbloom */ 92725703Sbloom if (stat(RMTDEBUG, &stbuf) != SUCCESS) { 92825703Sbloom Debug = 0; 92925703Sbloom return; 93025703Sbloom } 93125703Sbloom if ((geteuid() != stbuf.st_uid) || /* We must own it */ 93225703Sbloom ((stbuf.st_mode & 0170700) != 040700)) { /* Directory, rwx */ 93325703Sbloom Debug = 0; 934*33945Srick syslog(LOG_ERR, "%s: invalid directory mode: %o", RMTDEBUG, 935*33945Srick stbuf.st_mode); 93625703Sbloom return; 93725703Sbloom } 93813639Ssam 93925703Sbloom if (parm == DBG_TEMP) { 94025703Sbloom sprintf(buf, "%s/%d", RMTDEBUG, getpid()); 94125703Sbloom temp = malloc(strlen (buf) + 1); 94225703Sbloom if (temp == CNULL) { 94325703Sbloom Debug = 0; 944*33945Srick syslog(LOG_ERR, "RMTDEBUG malloc failed: %m"); 945*33945Srick cleanup(FAIL); 94625703Sbloom } 94725703Sbloom strcpy(temp, buf); 94825703Sbloom } else 94925703Sbloom sprintf(buf, "%s/%s", RMTDEBUG, Rmtname); 95013639Ssam 95125703Sbloom unlink(buf); 95225703Sbloom if (freopen(buf, "w", stderr) != stderr) { 95325703Sbloom Debug = 0; 954*33945Srick syslog(LOG_ERR, "RMTDEBUG freopen(%s) failed: %m", buf); 955*33945Srick cleanup(FAIL); 95625703Sbloom } 95725703Sbloom setbuf(stderr, CNULL); 95825703Sbloom auditopen = 1; 95913639Ssam } 96013639Ssam 96123590Sbloom /* 96225703Sbloom * catch SIGALRM routine 96313639Ssam */ 96413639Ssam timeout() 96513639Ssam { 96623590Sbloom extern int HaveSentHup; 96723590Sbloom if (!HaveSentHup) { 96823590Sbloom logent(Rmtname, "TIMEOUT"); 96923590Sbloom if (*Rmtname && strncmp(Rmtname, Myname, MAXBASENAME)) { 97023590Sbloom US_SST(us_s_tmot); 97123590Sbloom systat(Rmtname, SS_FAIL, "TIMEOUT"); 97223590Sbloom } 97317767Sralph } 97413639Ssam longjmp(Sjbuf, 1); 97513639Ssam } 97613639Ssam 97713639Ssam static char * 97813639Ssam pskip(p) 97913639Ssam register char *p; 98013639Ssam { 98117767Sralph while(*p && *p != ' ') 98213639Ssam ++p; 98323590Sbloom while(*p && *p == ' ') 98417767Sralph *p++ = 0; 98517767Sralph return p; 98613639Ssam } 987