113639Ssam #ifndef lint 2*25703Sbloom static char sccsid[] = "@(#)cico.c 5.11 (Berkeley) 01/06/86"; 313639Ssam #endif 413639Ssam 523590Sbloom #include <signal.h> 613639Ssam #include "uucp.h" 713639Ssam #include <setjmp.h> 817767Sralph #ifdef USG 913639Ssam #include <termio.h> 1013639Ssam #endif 1117767Sralph #ifndef USG 1213639Ssam #include <sgtty.h> 1313639Ssam #endif 1417767Sralph #ifdef BSDTCP 1517767Sralph #include <netdb.h> 1617767Sralph #include <netinet/in.h> 1717767Sralph #include <sys/socket.h> 1817767Sralph #endif BSDTCP 1917767Sralph #include <sys/stat.h> 2017767Sralph #include "uust.h" 2117767Sralph #include "uusub.h" 2213639Ssam 2323590Sbloom #if defined(VMS) && defined(BSDTCP) 2423590Sbloom #define NOGETPEER 2523590Sbloom #endif 2623590Sbloom 2723590Sbloom #ifdef BSD2_9 2823590Sbloom #define NOGETPEER 2923590Sbloom #endif 3023590Sbloom 3117767Sralph jmp_buf Sjbuf; 3217767Sralph jmp_buf Pipebuf; 3313639Ssam 3417767Sralph /* call fail text */ 3513639Ssam char *Stattext[] = { 3613639Ssam "", 3713639Ssam "BAD SYSTEM", 3817767Sralph "WRONG TIME TO CALL", 3913639Ssam "SYSTEM LOCKED", 4013639Ssam "NO DEVICE", 41*25703Sbloom "CALL FAILED", 4213639Ssam "LOGIN FAILED", 4313639Ssam "BAD SEQUENCE" 4417767Sralph }; 4513639Ssam 4617767Sralph /* call fail codes */ 4717767Sralph int Stattype[] = { 4817767Sralph 0, 4917767Sralph 0, 5017767Sralph SS_WRONGTIME, 5117767Sralph 0, 5217767Sralph SS_NODEVICE, 5317767Sralph SS_FAIL, 5417767Sralph SS_FAIL, 5517767Sralph SS_BADSEQ 5617767Sralph }; 5713639Ssam 58*25703Sbloom /* Arguments to setdebug(): */ 59*25703Sbloom #define DBG_TEMP 0 /* Create a temporary audit file */ 60*25703Sbloom #define DBG_PERM 1 /* Create a permanent audit file */ 61*25703Sbloom #define DBG_CLEAN 2 /* Cleanup, discard temp file */ 6213639Ssam 6317767Sralph int ReverseRole = 0; 6417767Sralph int Role = SLAVE; 6517767Sralph int onesys = 0; 6618616Sralph int turntime = 30 * 60; /* 30 minutes expressed in seconds */ 67*25703Sbloom char *ttyn = NULL; 6817767Sralph extern int LocalOnly; 69*25703Sbloom extern int errno; 7018616Sralph extern char MaxGrade, DefMaxGrade; 7118616Sralph extern char Myfullname[]; 7217767Sralph 7317767Sralph #ifdef USG 7413639Ssam struct termio Savettyb; 7513639Ssam #endif 7617767Sralph #ifndef USG 7713639Ssam struct sgttyb Savettyb; 7813639Ssam #endif 7913639Ssam 80*25703Sbloom /* 81*25703Sbloom * this program is used to place a call to a 8213639Ssam * remote machine, login, and copy files between the two machines. 8313639Ssam */ 8413639Ssam main(argc, argv) 85*25703Sbloom int argc; 8613639Ssam register char *argv[]; 8713639Ssam { 8813639Ssam register int ret; 8913639Ssam int seq; 9013639Ssam char wkpre[NAMESIZE], file[NAMESIZE]; 91*25703Sbloom char msg[MAXFULLNAME], *q; 9213639Ssam register char *p; 93*25703Sbloom extern onintr(), timeout(), dbg_signal(); 9413639Ssam extern char *pskip(); 9523725Sbloom char rflags[MAXFULLNAME]; 9623590Sbloom #ifdef NOGETPEER 9717767Sralph u_long Hostnumber = 0; 9823590Sbloom #endif NOGETPEER 9913639Ssam 10013639Ssam strcpy(Progname, "uucico"); 10113639Ssam 10213639Ssam signal(SIGINT, onintr); 10313639Ssam signal(SIGHUP, onintr); 10413639Ssam signal(SIGQUIT, onintr); 10513639Ssam signal(SIGTERM, onintr); 10613639Ssam signal(SIGPIPE, onintr); /* 4.1a tcp-ip stupidity */ 107*25703Sbloom signal(SIGFPE, dbg_signal); 10813639Ssam ret = guinfo(getuid(), User, msg); 10913639Ssam strcpy(Loginuser, User); 11023590Sbloom uucpname(Myname); 11117767Sralph ASSERT(ret == 0, "BAD UID", CNULL, ret); 11213639Ssam 113*25703Sbloom setbuf (stderr, CNULL); 114*25703Sbloom 115*25703Sbloom rflags[0] = '\0'; 11613639Ssam umask(WFMASK); 11713639Ssam strcpy(Rmtname, Myname); 11813639Ssam Ifn = Ofn = -1; 11913639Ssam while(argc>1 && argv[1][0] == '-'){ 12013639Ssam switch(argv[1][1]){ 12113639Ssam case 'd': 12213639Ssam Spool = &argv[1][2]; 12313639Ssam break; 12413639Ssam case 'g': 12518616Sralph case 'p': 12618616Sralph MaxGrade = DefMaxGrade = argv[1][2]; 12713639Ssam break; 12813639Ssam case 'r': 12913639Ssam Role = atoi(&argv[1][2]); 13013639Ssam break; 13117767Sralph case 'R': 13217767Sralph ReverseRole++; 13317767Sralph Role = MASTER; 13417767Sralph break; 13513639Ssam case 's': 13623590Sbloom strncpy(Rmtname, &argv[1][2], MAXBASENAME); 13723590Sbloom Rmtname[MAXBASENAME] = '\0'; 13813639Ssam if (Rmtname[0] != '\0') 13913639Ssam onesys = 1; 14013639Ssam break; 14113639Ssam case 'x': 14213639Ssam Debug = atoi(&argv[1][2]); 14313639Ssam if (Debug <= 0) 14413639Ssam Debug = 1; 145*25703Sbloom strcat(rflags, argv[1]); 14613639Ssam break; 14718616Sralph case 't': 14818616Sralph turntime = atoi(&argv[1][2])*60;/* minutes to seconds */ 14918616Sralph break; 15017767Sralph case 'L': /* local calls only */ 15117767Sralph LocalOnly++; 15217767Sralph break; 15323590Sbloom #ifdef NOGETPEER 15417767Sralph case 'h': 15517767Sralph Hostnumber = inet_addr(&argv[1][2]); 15617767Sralph break; 15723590Sbloom #endif NOGETPEER 15813639Ssam default: 15917767Sralph printf("unknown flag %s (ignored)\n", argv[1]); 16013639Ssam break; 16113639Ssam } 16213639Ssam --argc; argv++; 16313639Ssam } 16413639Ssam 16517767Sralph while (argc > 1) { 166*25703Sbloom fprintf(stderr, "unknown argument %s (ignored)\n", argv[1]); 16717767Sralph --argc; argv++; 16817767Sralph } 16917767Sralph 17025124Sbloom /* Try to run as uucp */ 17117767Sralph setgid(getegid()); 17217767Sralph setuid(geteuid()); 17317767Sralph #ifdef TIOCNOTTY 17417767Sralph /* 17517767Sralph * detach uucico from controlling terminal 17617767Sralph * to defend against rlogind sending us a SIGKILL (!!!) 17717767Sralph */ 17817767Sralph if (Role == MASTER && (ret = open("/dev/tty", 2)) >= 0) { 17917767Sralph ioctl(ret, TIOCNOTTY, STBNULL); 18017767Sralph close(ret); 18117767Sralph } 18217767Sralph #endif TIOCNOTTY 18317767Sralph #ifdef BSD4_2 18425517Stef if (getpgrp(0) == 0) { /* We have no controlling terminal */ 18517767Sralph setpgrp(0, getpid()); 18617767Sralph } 18717767Sralph #endif BSD4_2 18817767Sralph 18917767Sralph ret = subchdir(Spool); 19017767Sralph ASSERT(ret >= 0, "CHDIR FAILED", Spool, ret); 19113639Ssam strcpy(Wrkdir, Spool); 19213639Ssam 193*25703Sbloom if (Debug) { 194*25703Sbloom if (Role == MASTER) 195*25703Sbloom chkdebug(); 196*25703Sbloom setdebug ((Role == SLAVE) ? DBG_TEMP : DBG_PERM); 197*25703Sbloom if (Debug > 0) 198*25703Sbloom logent ("Local Enabled", "DEBUG"); 199*25703Sbloom } 200*25703Sbloom 201*25703Sbloom /* 202*25703Sbloom * First time through: If we're the slave, do initial checking. 203*25703Sbloom */ 20413639Ssam if (Role == SLAVE) { 20517767Sralph /* check for /etc/nologin */ 20625124Sbloom if (access(NOLOGIN, 0) == 0) { 20717767Sralph logent(NOLOGIN, "UUCICO SHUTDOWN"); 20823590Sbloom if (Debug > 4) 20917767Sralph logent("DEBUGGING", "continuing anyway"); 21017767Sralph else 21117767Sralph cleanup(1); 21217767Sralph } 213*25703Sbloom Ifn = 0; 214*25703Sbloom Ofn = 1; 21517767Sralph #ifdef TCPIP 21617767Sralph /* 21717767Sralph * Determine if we are on TCPIP 21817767Sralph */ 219*25703Sbloom if (isatty(Ifn) < 0) { 22017767Sralph IsTcpIp = 1; 22117767Sralph DEBUG(4, "TCPIP connection -- ioctl-s disabled\n", CNULL); 22223590Sbloom } else 22323590Sbloom IsTcpIp = 0; 22417767Sralph #endif TCPIP 22513639Ssam /* initial handshake */ 22613639Ssam onesys = 1; 22717767Sralph if (!IsTcpIp) { 22817767Sralph #ifdef USG 229*25703Sbloom ret = ioctl(Ifn, TCGETA, &Savettyb); 23013639Ssam Savettyb.c_cflag = (Savettyb.c_cflag & ~CS8) | CS7; 23113639Ssam Savettyb.c_oflag |= OPOST; 23213639Ssam Savettyb.c_lflag |= (ISIG|ICANON|ECHO); 23317767Sralph #else !USG 234*25703Sbloom ret = ioctl(Ifn, TIOCGETP, &Savettyb); 23513639Ssam Savettyb.sg_flags |= ECHO; 23613639Ssam Savettyb.sg_flags &= ~RAW; 23717767Sralph #endif !USG 238*25703Sbloom ttyn = ttyname(Ifn); 23913639Ssam } 24013639Ssam fixmode(Ifn); 24125517Stef getbaud(Ifn); 242*25703Sbloom 243*25703Sbloom /* 244*25703Sbloom * Initial Message -- tell them we're here, and who we are. 245*25703Sbloom */ 24618616Sralph sprintf(msg, "here=%s", Myfullname); 24717767Sralph omsg('S', msg, Ofn); 24813639Ssam signal(SIGALRM, timeout); 24913639Ssam alarm(MAXMSGTIME); 25013639Ssam if (setjmp(Sjbuf)) { 25113639Ssam /* timed out */ 25217767Sralph if (!IsTcpIp) { 25317767Sralph #ifdef USG 254*25703Sbloom ret = ioctl(Ifn, TCSETA, &Savettyb); 255*25703Sbloom 25623590Sbloom #else !USG 257*25703Sbloom ret = ioctl(Ifn, TIOCSETP, &Savettyb); 25823590Sbloom #endif !USG 25913639Ssam } 26017767Sralph cleanup(0); 26113639Ssam } 26213639Ssam for (;;) { 26313639Ssam ret = imsg(msg, Ifn); 264*25703Sbloom if (ret != SUCCESS) { 26513639Ssam alarm(0); 26617767Sralph if (!IsTcpIp) { 26717767Sralph #ifdef USG 268*25703Sbloom ret = ioctl(Ifn, TCSETA, &Savettyb); 26923590Sbloom #else !USG 270*25703Sbloom ret = ioctl(Ifn, TIOCSETP, &Savettyb); 27123590Sbloom #endif !USG 27213639Ssam } 27317767Sralph cleanup(0); 27413639Ssam } 27513639Ssam if (msg[0] == 'S') 27613639Ssam break; 27713639Ssam } 27813639Ssam alarm(0); 27913639Ssam q = &msg[1]; 28013639Ssam p = pskip(q); 28123590Sbloom strncpy(Rmtname, q, MAXBASENAME); 28223590Sbloom Rmtname[MAXBASENAME] = '\0'; 283*25703Sbloom 284*25703Sbloom /* 285*25703Sbloom * Now that we know who they are, give the audit file the right 286*25703Sbloom * name. 287*25703Sbloom */ 288*25703Sbloom setdebug (DBG_PERM); 28913639Ssam DEBUG(4, "sys-%s\n", Rmtname); 29023725Sbloom /* The versys will also do an alias on the incoming name */ 29123725Sbloom if (versys(&Rmtname)) { 29223725Sbloom /* If we don't know them, we won't talk to them... */ 29323590Sbloom #ifdef NOSTRANGERS 29423590Sbloom logent(Rmtname, "UNKNOWN HOST"); 29523590Sbloom omsg('R', "You are unknown to me", Ofn); 29623590Sbloom cleanup(0); 29723725Sbloom #endif NOSTRANGERS 29823590Sbloom } 29917767Sralph #ifdef BSDTCP 30017767Sralph /* we must make sure they are really who they say they 30117767Sralph * are. We compare the hostnumber with the number in the hosts 30217767Sralph * table for the site they claim to be. 30317767Sralph */ 30417767Sralph if (IsTcpIp) { 30517767Sralph struct hostent *hp; 30617767Sralph char *cpnt, *inet_ntoa(); 307*25703Sbloom int fromlen; 30817767Sralph struct sockaddr_in from; 30925124Sbloom extern char PhoneNumber[]; 31017767Sralph 31123590Sbloom #ifdef NOGETPEER 31223590Sbloom from.sin_addr.s_addr = Hostnumber; 31323590Sbloom from.sin_family = AF_INET; 31423590Sbloom #else !NOGETPEER 315*25703Sbloom fromlen = sizeof(from); 316*25703Sbloom if (getpeername(Ifn, &from, &fromlen) < 0) { 31717767Sralph logent(Rmtname, "NOT A TCP CONNECTION"); 31817767Sralph omsg('R', "NOT TCP", Ofn); 31917767Sralph cleanup(0); 32017767Sralph } 32123590Sbloom #endif !NOGETPEER 32217767Sralph hp = gethostbyaddr(&from.sin_addr, 32317767Sralph sizeof (struct in_addr), from.sin_family); 324*25703Sbloom if (hp == NULL) { 32517767Sralph /* security break or just old host table? */ 32617767Sralph logent(Rmtname, "UNKNOWN IP-HOST Name ="); 32717767Sralph cpnt = inet_ntoa(from.sin_addr), 32817767Sralph logent(cpnt, "UNKNOWN IP-HOST Number ="); 32917767Sralph sprintf(wkpre, "%s/%s isn't in my host table", 33017767Sralph Rmtname, cpnt); 33117767Sralph omsg('R' ,wkpre ,Ofn); 33217767Sralph cleanup(0); 33317767Sralph } 334*25703Sbloom if (Debug > 99) 33517767Sralph logent(Rmtname,"Request from IP-Host name ="); 33625124Sbloom /* 33725124Sbloom * The following is to determine if the name given us by 33825124Sbloom * the Remote uucico matches any of the names 33917767Sralph * given its network number (remote machine) in our 34017767Sralph * host table. 34125124Sbloom * We could check the aliases, but that won't work in 34225124Sbloom * all cases (like if you are running the domain 34325124Sbloom * server, where you don't get any aliases). The only 34425124Sbloom * reliable way I can think of that works in ALL cases 34525124Sbloom * is too look up the site in L.sys and see if the 34625124Sbloom * sitename matches what we would call him if we 34725124Sbloom * originated the call. 34817767Sralph */ 34925124Sbloom /* PhoneNumber contains the official network name of the host we are checking. (set in versys.c) */ 35025124Sbloom if (sncncmp(PhoneNumber, hp->h_name, SYSNSIZE) == 0) { 35117767Sralph if (Debug > 99) 35217767Sralph logent(q,"Found in host Tables"); 35325124Sbloom } else { 35425124Sbloom logent(hp->h_name, "FORGED HOSTNAME"); 35525124Sbloom logent(inet_ntoa(from.sin_addr), "ORIGINATED AT"); 35625124Sbloom logent(PhoneNumber, "SHOULD BE"); 35725124Sbloom sprintf(wkpre, "You're not who you claim to be: %s != %s", hp->h_name, PhoneNumber); 35825124Sbloom omsg('R', wkpre, Ofn); 35925124Sbloom cleanup(0); 36017767Sralph } 36117767Sralph } 36217767Sralph #endif BSDTCP 36317767Sralph 364*25703Sbloom if (mlock(Rmtname)) { 36513639Ssam omsg('R', "LCK", Ofn); 36613639Ssam cleanup(0); 36713639Ssam } 36813639Ssam else if (callback(Loginuser)) { 36913639Ssam signal(SIGINT, SIG_IGN); 37013639Ssam signal(SIGHUP, SIG_IGN); 37113639Ssam omsg('R', "CB", Ofn); 37213639Ssam logent("CALLBACK", "REQUIRED"); 37313639Ssam /* set up for call back */ 37417767Sralph systat(Rmtname, SS_CALLBACK, "CALLING BACK"); 37513639Ssam gename(CMDPRE, Rmtname, 'C', file); 37613639Ssam close(creat(subfile(file), 0666)); 37713639Ssam xuucico(Rmtname); 37813639Ssam cleanup(0); 37913639Ssam } 38013639Ssam seq = 0; 38113639Ssam while (*p == '-') { 38213639Ssam q = pskip(p); 38313639Ssam switch(*(++p)) { 38413639Ssam case 'x': 385*25703Sbloom if (Debug == 0) { 386*25703Sbloom Debug = atoi(++p); 387*25703Sbloom if (Debug <= 0) 388*25703Sbloom Debug = 1; 389*25703Sbloom setdebug(DBG_PERM); 390*25703Sbloom if (Debug > 0) 391*25703Sbloom logent("Remote Enabled", "DEBUG"); 392*25703Sbloom } else { 393*25703Sbloom DEBUG(1, "Remote debug request ignored\n", 394*25703Sbloom CNULL); 395*25703Sbloom } 39613639Ssam break; 39713639Ssam case 'Q': 39813639Ssam seq = atoi(++p); 39913639Ssam break; 40018616Sralph case 'p': 40118616Sralph MaxGrade = DefMaxGrade = *++p; 40218616Sralph DEBUG(4, "MaxGrade set to %c\n", MaxGrade); 40318616Sralph break; 40423590Sbloom case 'v': 40523590Sbloom if (strncmp(p, "grade", 5) == 0) { 40623590Sbloom p += 6; 40723590Sbloom MaxGrade = DefMaxGrade = *p++; 40823590Sbloom DEBUG(4, "MaxGrade set to %c\n", MaxGrade); 40923590Sbloom } 41023590Sbloom break; 41113639Ssam default: 41213639Ssam break; 41313639Ssam } 41413639Ssam p = q; 41513639Ssam } 41613639Ssam if (callok(Rmtname) == SS_BADSEQ) { 41713639Ssam logent("BADSEQ", "PREVIOUS"); 41813639Ssam omsg('R', "BADSEQ", Ofn); 41913639Ssam cleanup(0); 42013639Ssam } 42117767Sralph #ifdef GNXSEQ 42213639Ssam if ((ret = gnxseq(Rmtname)) == seq) { 42313639Ssam omsg('R', "OK", Ofn); 42413639Ssam cmtseq(); 42517767Sralph } else { 42617767Sralph #else !GNXSEQ 42717767Sralph if (seq == 0) 42817767Sralph omsg('R', "OK", Ofn); 42913639Ssam else { 43017767Sralph #endif !GNXSEQ 43113639Ssam systat(Rmtname, Stattype[7], Stattext[7]); 43223590Sbloom logent("BAD SEQ", "FAILED HANDSHAKE"); 43317767Sralph #ifdef GNXSEQ 43413639Ssam ulkseq(); 43517767Sralph #endif GNXSEQ 43613639Ssam omsg('R', "BADSEQ", Ofn); 43713639Ssam cleanup(0); 43813639Ssam } 43913639Ssam if (ttyn != NULL) 44013639Ssam chmod(ttyn, 0600); 44113639Ssam } 44217767Sralph 44313639Ssam loop: 44417767Sralph if(setjmp(Pipebuf)) { /* come here on SIGPIPE */ 44517767Sralph clsacu(); 44617767Sralph close(Ofn); 44717767Sralph close(Ifn); 44817767Sralph Ifn = Ofn = -1; 44917767Sralph rmlock(CNULL); 45017767Sralph sleep(3); 45117767Sralph } 45213639Ssam if (!onesys) { 45313639Ssam ret = gnsys(Rmtname, Spool, CMDPRE); 454*25703Sbloom setdebug(DBG_PERM); 45513639Ssam if (ret == FAIL) 45613639Ssam cleanup(100); 45723590Sbloom if (ret == SUCCESS) 45813639Ssam cleanup(0); 45917767Sralph } else if (Role == MASTER && callok(Rmtname) != 0) { 46013639Ssam logent("SYSTEM STATUS", "CAN NOT CALL"); 46113639Ssam cleanup(0); 46213639Ssam } 46313639Ssam 46423590Sbloom sprintf(wkpre, "%c.%.*s", CMDPRE, SYSNSIZE, Rmtname); 46513639Ssam 46617767Sralph signal(SIGINT, SIG_IGN); 46717767Sralph signal(SIGQUIT, SIG_IGN); 46813639Ssam if (Role == MASTER) { 46917767Sralph /* check for /etc/nologin */ 47025124Sbloom if (access(NOLOGIN, 0) == 0) { 47117767Sralph logent(NOLOGIN, "UUCICO SHUTDOWN"); 47223590Sbloom if (Debug > 4) 47317767Sralph logent("DEBUGGING", "continuing anyway"); 47417767Sralph else 47517767Sralph cleanup(1); 47617767Sralph } 47713639Ssam /* master part */ 47813639Ssam signal(SIGHUP, SIG_IGN); 47913639Ssam if (Ifn != -1 && Role == MASTER) { 48013639Ssam write(Ofn, EOTMSG, strlen(EOTMSG)); 48113639Ssam clsacu(); 48213639Ssam close(Ofn); 48313639Ssam close(Ifn); 48413639Ssam Ifn = Ofn = -1; 48513639Ssam rmlock(CNULL); 48613639Ssam sleep(3); 48713639Ssam } 48813639Ssam sprintf(msg, "call to %s ", Rmtname); 48925124Sbloom if (mlock(Rmtname) != SUCCESS) { 49013639Ssam logent(msg, "LOCKED"); 49117767Sralph US_SST(us_s_lock); 49213639Ssam goto next; 49313639Ssam } 49413639Ssam Ofn = Ifn = conn(Rmtname); 49513639Ssam if (Ofn < 0) { 49617767Sralph if (Ofn != CF_TIME) 49717767Sralph logent(msg, _FAILED); 49817767Sralph /* avoid excessive 'wrong time' info */ 49923590Sbloom if (Stattype[-Ofn] != SS_WRONGTIME){ 50017767Sralph systat(Rmtname, Stattype[-Ofn], Stattext[-Ofn]); 50117767Sralph US_SST(-Ofn); 50217767Sralph UB_SST(-Ofn); 50317767Sralph } 50413639Ssam goto next; 50517767Sralph } else { 50613639Ssam logent(msg, "SUCCEEDED"); 50717767Sralph US_SST(us_s_cok); 50817767Sralph UB_SST(ub_ok); 50913639Ssam } 51017767Sralph #ifdef TCPIP 51117767Sralph /* 51217767Sralph * Determine if we are on TCPIP 51317767Sralph */ 514*25703Sbloom if (isatty(Ifn) == 0) { 51517767Sralph IsTcpIp = 1; 51617767Sralph DEBUG(4, "TCPIP connection -- ioctl-s disabled\n", CNULL); 51723590Sbloom } else 51823590Sbloom IsTcpIp = 0; 51917767Sralph #endif 52017767Sralph 52113639Ssam if (setjmp(Sjbuf)) 52213639Ssam goto next; 52313639Ssam signal(SIGALRM, timeout); 52413639Ssam alarm(2 * MAXMSGTIME); 52513639Ssam for (;;) { 52613639Ssam ret = imsg(msg, Ifn); 52713639Ssam if (ret != 0) { 52813639Ssam alarm(0); 52917767Sralph logent("imsg 1", _FAILED); 53017767Sralph goto Failure; 53113639Ssam } 53213639Ssam if (msg[0] == 'S') 53313639Ssam break; 53413639Ssam } 53513639Ssam alarm(MAXMSGTIME); 53617767Sralph #ifdef GNXSEQ 53713639Ssam seq = gnxseq(Rmtname); 53817767Sralph #else !GNXSEQ 53917767Sralph seq = 0; 54017767Sralph #endif !GNXSEQ 54118616Sralph if (MaxGrade != '\177') { 54223725Sbloom char buf[MAXFULLNAME]; 54323590Sbloom sprintf(buf, " -p%c -vgrade=%c", MaxGrade, MaxGrade); 54418616Sralph strcat(rflags, buf); 54518616Sralph } 54618616Sralph 54723590Sbloom sprintf(msg, "%s -Q%d %s", Myname, seq, rflags); 54823590Sbloom if (MaxGrade != '\177') 54923590Sbloom DEBUG(2, "Max Grade this transfer is %c\n", MaxGrade); 55013639Ssam omsg('S', msg, Ofn); 55113639Ssam for (;;) { 55213639Ssam ret = imsg(msg, Ifn); 55313639Ssam DEBUG(4, "msg-%s\n", msg); 55417767Sralph if (ret != SUCCESS) { 55513639Ssam alarm(0); 55617767Sralph #ifdef GNXSEQ 55713639Ssam ulkseq(); 55817767Sralph #endif GNXSEQ 55917767Sralph logent("imsg 2", _FAILED); 56017767Sralph goto Failure; 56113639Ssam } 56213639Ssam if (msg[0] == 'R') 56313639Ssam break; 56413639Ssam } 56513639Ssam alarm(0); 56613639Ssam if (msg[1] == 'B') { 56713639Ssam /* bad sequence */ 56823590Sbloom logent("BAD SEQ", "FAILED HANDSHAKE"); 56917767Sralph US_SST(us_s_hand); 57017767Sralph systat(Rmtname, SS_BADSEQ, Stattext[SS_BADSEQ]); 57117767Sralph #ifdef GNXSEQ 57213639Ssam ulkseq(); 57317767Sralph #endif GNXSEQ 57413639Ssam goto next; 57513639Ssam } 57613639Ssam if (strcmp(&msg[1], "OK") != SAME) { 57723590Sbloom logent(&msg[1], "FAILED HANDSHAKE"); 57817767Sralph US_SST(us_s_hand); 57917767Sralph #ifdef GNXSEQ 58013639Ssam ulkseq(); 58117767Sralph #endif GNXSEQ 58217767Sralph systat(Rmtname, SS_INPROGRESS, 58317767Sralph strcmp(&msg[1], "CB") == SAME? 58423590Sbloom "AWAITING CALLBACK": "FAILED HANDSHAKE"); 58513639Ssam goto next; 58613639Ssam } 58717767Sralph #ifdef GNXSEQ 58813639Ssam cmtseq(); 58917767Sralph #endif GNXSEQ 59013639Ssam } 59117767Sralph DEBUG(1, "Rmtname %s, ", Rmtname); 59213639Ssam DEBUG(1, "Role %s, ", Role ? "MASTER" : "SLAVE"); 59313639Ssam DEBUG(1, "Ifn - %d, ", Ifn); 59413639Ssam DEBUG(1, "Loginuser - %s\n", Loginuser); 59513639Ssam 596*25703Sbloom ttyn = ttyname(Ifn); 597*25703Sbloom 59813639Ssam alarm(MAXMSGTIME); 59918616Sralph if (ret=setjmp(Sjbuf)) 60013639Ssam goto Failure; 60113639Ssam ret = startup(Role); 60213639Ssam alarm(0); 60313639Ssam if (ret != SUCCESS) { 60417767Sralph logent("startup", _FAILED); 60513639Ssam Failure: 60617767Sralph US_SST(us_s_start); 60718616Sralph systat(Rmtname, SS_FAIL, ret > 0 ? "CONVERSATION FAILED" : 60818616Sralph "STARTUP FAILED"); 60913639Ssam goto next; 61017767Sralph } else { 611*25703Sbloom if (ttyn != NULL) { 612*25703Sbloom char startupmsg[BUFSIZ]; 613*25703Sbloom extern int linebaudrate; 614*25703Sbloom sprintf(startupmsg, "startup %s %d baud", &ttyn[5], 615*25703Sbloom linebaudrate); 616*25703Sbloom logent(startupmsg, "OK"); 617*25703Sbloom } else 618*25703Sbloom logent("startup", "OK"); 61917767Sralph US_SST(us_s_gress); 62013639Ssam systat(Rmtname, SS_INPROGRESS, "TALKING"); 62113639Ssam ret = cntrl(Role, wkpre); 62213639Ssam DEBUG(1, "cntrl - %d\n", ret); 62313639Ssam signal(SIGINT, SIG_IGN); 62413639Ssam signal(SIGHUP, SIG_IGN); 62513639Ssam signal(SIGALRM, timeout); 62617767Sralph if (ret == SUCCESS) { 62713639Ssam logent("conversation complete", "OK"); 62817767Sralph US_SST(us_s_ok); 62913639Ssam rmstat(Rmtname); 63013639Ssam 63117767Sralph } else { 63217767Sralph logent("conversation complete", _FAILED); 63317767Sralph US_SST(us_s_cf); 63417767Sralph systat(Rmtname, SS_FAIL, "CONVERSATION FAILED"); 63513639Ssam } 63613639Ssam alarm(MAXMSGTIME); 63713639Ssam DEBUG(4, "send OO %d,", ret); 63813639Ssam if (!setjmp(Sjbuf)) { 63913639Ssam for (;;) { 64013639Ssam omsg('O', "OOOOO", Ofn); 64113639Ssam ret = imsg(msg, Ifn); 64213639Ssam if (ret != 0) 64313639Ssam break; 64413639Ssam if (msg[0] == 'O') 64513639Ssam break; 64613639Ssam } 64713639Ssam } 64813639Ssam alarm(0); 64917767Sralph clsacu(); 65017767Sralph rmlock(CNULL); 65113639Ssam } 65213639Ssam next: 65313639Ssam if (!onesys) { 65413639Ssam goto loop; 65513639Ssam } 65613639Ssam cleanup(0); 65713639Ssam } 65813639Ssam 65917767Sralph #ifndef USG 66013639Ssam struct sgttyb Hupvec; 66113639Ssam #endif 66213639Ssam 663*25703Sbloom /* 664*25703Sbloom * cleanup and exit with "code" status 66513639Ssam */ 66613639Ssam cleanup(code) 66713639Ssam register int code; 66813639Ssam { 66913639Ssam signal(SIGINT, SIG_IGN); 67013639Ssam signal(SIGHUP, SIG_IGN); 67113639Ssam rmlock(CNULL); 672*25703Sbloom sleep(5); /* Wait for any pending output */ 67313639Ssam clsacu(); 67413639Ssam logcls(); 67513639Ssam if (Role == SLAVE) { 67617767Sralph if (!IsTcpIp) { 67717767Sralph #ifdef USG 67813639Ssam Savettyb.c_cflag |= HUPCL; 67923590Sbloom (void) ioctl(0, TCSETA, &Savettyb); 68017767Sralph #else !USG 68123590Sbloom (void) ioctl(0, TIOCHPCL, STBNULL); 68218616Sralph #ifdef TIOCSDTR 68323590Sbloom (void) ioctl(0, TIOCCDTR, STBNULL); 68418616Sralph sleep(2); 68523590Sbloom (void) ioctl(0, TIOCSDTR, STBNULL); 68618616Sralph #else !TIOCSDTR 68723590Sbloom (void) ioctl(0, TIOCGETP, &Hupvec); 68813639Ssam Hupvec.sg_ispeed = B0; 68913639Ssam Hupvec.sg_ospeed = B0; 69023590Sbloom (void) ioctl(0, TIOCSETP, &Hupvec); 691*25703Sbloom #endif !TIOCSDTR 69213639Ssam sleep(2); 69323590Sbloom (void) ioctl(0, TIOCSETP, &Savettyb); 69417767Sralph /* make *sure* exclusive access is off */ 69523590Sbloom (void) ioctl(0, TIOCNXCL, STBNULL); 69617767Sralph #endif !USG 69713639Ssam } 69813639Ssam if (ttyn != NULL) 69913639Ssam chmod(ttyn, 0600); 70013639Ssam } 70113639Ssam if (Ofn != -1) { 70213639Ssam if (Role == MASTER) 70313639Ssam write(Ofn, EOTMSG, strlen(EOTMSG)); 70413639Ssam close(Ifn); 70513639Ssam close(Ofn); 70613639Ssam } 70718616Sralph #ifdef DIALINOUT 70818616Sralph /* reenable logins on dialout */ 70918616Sralph reenable(); 71018616Sralph #endif DIALINOUT 71113639Ssam if (code == 0) 71213639Ssam xuuxqt(); 71317767Sralph else 71417767Sralph DEBUG(1, "exit code %d\n", code); 715*25703Sbloom setdebug (DBG_CLEAN); 71613639Ssam exit(code); 71713639Ssam } 71813639Ssam 719*25703Sbloom /* 720*25703Sbloom * on interrupt - remove locks and exit 72113639Ssam */ 72213639Ssam 72313639Ssam onintr(inter) 72413639Ssam register int inter; 72513639Ssam { 72613639Ssam char str[30]; 72713639Ssam signal(inter, SIG_IGN); 72813639Ssam sprintf(str, "SIGNAL %d", inter); 72913639Ssam logent(str, "CAUGHT"); 73017767Sralph US_SST(us_s_intr); 73123590Sbloom if (*Rmtname && strncmp(Rmtname, Myname, MAXBASENAME)) 73217767Sralph systat(Rmtname, SS_FAIL, str); 73317767Sralph if (inter == SIGPIPE && !onesys) 73417767Sralph longjmp(Pipebuf, 1); 73513639Ssam cleanup(inter); 73613639Ssam } 73713639Ssam 73813639Ssam /* 73913639Ssam * Catch a special signal 74013639Ssam * (SIGFPE, ugh), and toggle debugging between 0 and 30. 74113639Ssam * Handy for looking in on long running uucicos. 74213639Ssam */ 743*25703Sbloom dbg_signal() 74413639Ssam { 745*25703Sbloom Debug = (Debug == 0) ? 30 : 0; 746*25703Sbloom setdebug(DBG_PERM); 747*25703Sbloom if (Debug > 0) 748*25703Sbloom logent("Signal Enabled", "DEBUG"); 749*25703Sbloom } 75017767Sralph 751*25703Sbloom 752*25703Sbloom /* 753*25703Sbloom * Check debugging requests, and open RMTDEBUG audit file if necessary. If an 754*25703Sbloom * audit file is needed, the parm argument indicates how to create the file: 755*25703Sbloom * 756*25703Sbloom * DBG_TEMP - Open a temporary file, with filename = RMTDEBUG/pid. 757*25703Sbloom * DBG_PERM - Open a permanent audit file, filename = RMTDEBUG/Rmtname. 758*25703Sbloom * If a temp file already exists, it is mv'ed to be permanent. 759*25703Sbloom * DBG_CLEAN - Cleanup; unlink temp files. 760*25703Sbloom * 761*25703Sbloom * Restrictions - this code can only cope with one open debug file at a time. 762*25703Sbloom * Each call creates a new file; if an old one of the same name exists it will 763*25703Sbloom * be overwritten. 764*25703Sbloom */ 765*25703Sbloom setdebug(parm) 766*25703Sbloom int parm; 767*25703Sbloom { 768*25703Sbloom char buf[BUFSIZ]; /* Buffer for building filenames */ 769*25703Sbloom static char *temp = NULL; /* Ptr to temporary file name */ 770*25703Sbloom static int auditopen = 0; /* Set to 1 when we open a file */ 771*25703Sbloom struct stat stbuf; /* File status buffer */ 772*25703Sbloom 773*25703Sbloom /* 774*25703Sbloom * If movement or cleanup of a temp file is indicated, we do it no 775*25703Sbloom * matter what. 776*25703Sbloom */ 777*25703Sbloom if (temp != CNULL && parm == DBG_PERM) { 778*25703Sbloom sprintf(buf, "%s/%s", RMTDEBUG, Rmtname); 779*25703Sbloom unlink(buf); 780*25703Sbloom if (link(temp, buf) != 0) { 78123590Sbloom Debug = 0; 782*25703Sbloom assert("RMTDEBUG LINK FAIL", temp, errno); 783*25703Sbloom cleanup(1); 784*25703Sbloom } 785*25703Sbloom parm = DBG_CLEAN; 78623590Sbloom } 787*25703Sbloom if (parm == DBG_CLEAN) { 788*25703Sbloom if (temp != CNULL) { 789*25703Sbloom unlink(temp); 790*25703Sbloom free(temp); 791*25703Sbloom temp = CNULL; 792*25703Sbloom } 793*25703Sbloom return; 794*25703Sbloom } 795*25703Sbloom 796*25703Sbloom if (Debug == 0) 797*25703Sbloom return; /* Gotta be in debug to come here. */ 798*25703Sbloom 799*25703Sbloom /* 800*25703Sbloom * If we haven't opened a file already, we can just return if it's 801*25703Sbloom * alright to use the stderr we came in with. We can if: 802*25703Sbloom * 803*25703Sbloom * Role == MASTER, and Stderr is a regular file, a TTY or a pipe. 804*25703Sbloom * 805*25703Sbloom * Caution: Detecting when stderr is a pipe is tricky, because the 4.2 806*25703Sbloom * man page for fstat(2) disagrees with reality, and System V leaves it 807*25703Sbloom * undefined, which means different implementations act differently. 808*25703Sbloom */ 809*25703Sbloom if (!auditopen && Role == MASTER) { 810*25703Sbloom if (isatty(fileno(stderr))) 811*25703Sbloom return; 812*25703Sbloom else if (fstat(fileno(stderr), &stbuf) == 0) { 813*25703Sbloom #ifdef USG 814*25703Sbloom /* Is Regular File or Fifo */ 815*25703Sbloom if ((stbuf.st_mode & 0060000) == 0) 816*25703Sbloom return; 817*25703Sbloom #else !USG 81817767Sralph #ifdef BSD4_2 819*25703Sbloom /* Is Regular File */ 820*25703Sbloom if ((stbuf.st_mode & S_IFMT) == S_IFREG || 821*25703Sbloom stbuf.st_mode == 0) /* Is a pipe */ 822*25703Sbloom return; 823*25703Sbloom #else !BSD4_2 824*25703Sbloom /* Is Regular File or Pipe */ 825*25703Sbloom if ((stbuf.st_mode & S_IFMT) == S_IFREG) 826*25703Sbloom return; 827*25703Sbloom #endif BSD4_2 828*25703Sbloom #endif USG 829*25703Sbloom } 83017767Sralph } 83113639Ssam 832*25703Sbloom /* 833*25703Sbloom * We need RMTDEBUG directory to do auditing. If the file doesn't exist, 834*25703Sbloom * then we forget about debugging; if it exists but has improper owner- 835*25703Sbloom * ship or modes, we gripe about it in ERRLOG. 836*25703Sbloom */ 837*25703Sbloom if (stat(RMTDEBUG, &stbuf) != SUCCESS) { 838*25703Sbloom Debug = 0; 839*25703Sbloom return; 840*25703Sbloom } 841*25703Sbloom if ((geteuid() != stbuf.st_uid) || /* We must own it */ 842*25703Sbloom ((stbuf.st_mode & 0170700) != 040700)) { /* Directory, rwx */ 843*25703Sbloom Debug = 0; 844*25703Sbloom assert("INVALID RMTDEBUG DIRECTORY:", RMTDEBUG, stbuf.st_mode); 845*25703Sbloom return; 846*25703Sbloom } 84713639Ssam 848*25703Sbloom if (parm == DBG_TEMP) { 849*25703Sbloom sprintf(buf, "%s/%d", RMTDEBUG, getpid()); 850*25703Sbloom temp = malloc(strlen (buf) + 1); 851*25703Sbloom if (temp == CNULL) { 852*25703Sbloom Debug = 0; 853*25703Sbloom assert("RMTDEBUG MALLOC ERROR:", temp, errno); 854*25703Sbloom cleanup(1); 855*25703Sbloom } 856*25703Sbloom strcpy(temp, buf); 857*25703Sbloom } else 858*25703Sbloom sprintf(buf, "%s/%s", RMTDEBUG, Rmtname); 85913639Ssam 860*25703Sbloom unlink(buf); 861*25703Sbloom if (freopen(buf, "w", stderr) != stderr) { 862*25703Sbloom Debug = 0; 863*25703Sbloom assert("FAILED RMTDEBUG FILE OPEN:", buf, errno); 864*25703Sbloom cleanup(1); 865*25703Sbloom } 866*25703Sbloom setbuf(stderr, CNULL); 867*25703Sbloom auditopen = 1; 86813639Ssam } 86913639Ssam 87023590Sbloom /* 871*25703Sbloom * catch SIGALRM routine 87213639Ssam */ 87313639Ssam timeout() 87413639Ssam { 87523590Sbloom extern int HaveSentHup; 87623590Sbloom if (!HaveSentHup) { 87723590Sbloom logent(Rmtname, "TIMEOUT"); 87823590Sbloom if (*Rmtname && strncmp(Rmtname, Myname, MAXBASENAME)) { 87923590Sbloom US_SST(us_s_tmot); 88023590Sbloom systat(Rmtname, SS_FAIL, "TIMEOUT"); 88123590Sbloom } 88217767Sralph } 88313639Ssam longjmp(Sjbuf, 1); 88413639Ssam } 88513639Ssam 88613639Ssam static char * 88713639Ssam pskip(p) 88813639Ssam register char *p; 88913639Ssam { 89017767Sralph while(*p && *p != ' ') 89113639Ssam ++p; 89223590Sbloom while(*p && *p == ' ') 89317767Sralph *p++ = 0; 89417767Sralph return p; 89513639Ssam } 896