148664Sbostic /*-
2*62391Sbostic * Copyright (c) 1985, 1993
3*62391Sbostic * The Regents of the University of California. All rights reserved.
448664Sbostic *
548664Sbostic * %sccs.include.proprietary.c%
648664Sbostic */
748664Sbostic
813639Ssam #ifndef lint
9*62391Sbostic static char sccsid[] = "@(#)cico.c 8.1 (Berkeley) 06/06/93";
1048664Sbostic #endif /* not lint */
1113639Ssam
1223590Sbloom #include <signal.h>
1313639Ssam #include "uucp.h"
1413639Ssam #include <setjmp.h>
1517767Sralph #ifdef USG
1613639Ssam #include <termio.h>
1733559Srick #include <fcntl.h>
1813639Ssam #endif
1917767Sralph #ifndef USG
2013639Ssam #include <sgtty.h>
2113639Ssam #endif
2217767Sralph #ifdef BSDTCP
2317767Sralph #include <netdb.h>
2417767Sralph #include <netinet/in.h>
2517767Sralph #include <sys/socket.h>
2617767Sralph #endif BSDTCP
2717767Sralph #include <sys/stat.h>
2833559Srick #ifdef BSD4_2
2933559Srick #include <sys/time.h>
3033559Srick #include <fcntl.h>
3133559Srick #else
3233559Srick #include <time.h>
3333559Srick #endif
3417767Sralph #include "uust.h"
3517767Sralph #include "uusub.h"
3637930Sbostic #include "pathnames.h"
3713639Ssam
3823590Sbloom #if defined(VMS) && defined(BSDTCP)
3923590Sbloom #define NOGETPEER
4023590Sbloom #endif
4123590Sbloom
4217767Sralph jmp_buf Sjbuf;
4317767Sralph jmp_buf Pipebuf;
4413639Ssam
4517767Sralph /* call fail text */
4613639Ssam char *Stattext[] = {
4713639Ssam "",
4813639Ssam "BAD SYSTEM",
4917767Sralph "WRONG TIME TO CALL",
5013639Ssam "SYSTEM LOCKED",
5113639Ssam "NO DEVICE",
5225703Sbloom "CALL FAILED",
5313639Ssam "LOGIN FAILED",
5413639Ssam "BAD SEQUENCE"
5517767Sralph };
5613639Ssam
5717767Sralph /* call fail codes */
5817767Sralph int Stattype[] = {
5917767Sralph 0,
6017767Sralph 0,
6117767Sralph SS_WRONGTIME,
6217767Sralph 0,
6317767Sralph SS_NODEVICE,
6417767Sralph SS_FAIL,
6517767Sralph SS_FAIL,
6617767Sralph SS_BADSEQ
6717767Sralph };
6813639Ssam
6925703Sbloom /* Arguments to setdebug(): */
7025703Sbloom #define DBG_TEMP 0 /* Create a temporary audit file */
7125703Sbloom #define DBG_PERM 1 /* Create a permanent audit file */
7225703Sbloom #define DBG_CLEAN 2 /* Cleanup, discard temp file */
7313639Ssam
7417767Sralph int ReverseRole = 0;
7517767Sralph int Role = SLAVE;
7633559Srick int InitialRole = SLAVE;
7733559Srick long StartTime;
7817767Sralph int onesys = 0;
7918616Sralph int turntime = 30 * 60; /* 30 minutes expressed in seconds */
8025703Sbloom char *ttyn = NULL;
8117767Sralph extern int LocalOnly;
8225703Sbloom extern int errno;
8318616Sralph extern char MaxGrade, DefMaxGrade;
8418616Sralph extern char Myfullname[];
8517767Sralph
8633559Srick long Bytes_Sent, Bytes_Received;
8733559Srick
8817767Sralph #ifdef USG
8913639Ssam struct termio Savettyb;
9013639Ssam #endif
9117767Sralph #ifndef USG
9213639Ssam struct sgttyb Savettyb;
9313639Ssam #endif
9413639Ssam
9534164Srick #define SETPROCTITLE
9634164Srick #ifdef SETPROCTITLE
9734164Srick char **Argv = NULL; /* pointer to argument vector */
9834164Srick char *LastArgv = NULL; /* end of argv */
9934164Srick #endif SETPROCTITLE
10034164Srick
10125703Sbloom /*
10225703Sbloom * this program is used to place a call to a
10313639Ssam * remote machine, login, and copy files between the two machines.
10413639Ssam */
main(argc,argv,envp)10534164Srick main(argc, argv, envp)
10625703Sbloom int argc;
10733945Srick char **argv;
10834164Srick char **envp;
10913639Ssam {
11013639Ssam register int ret;
11113639Ssam int seq;
11213639Ssam char wkpre[NAMESIZE], file[NAMESIZE];
11325703Sbloom char msg[MAXFULLNAME], *q;
11413639Ssam register char *p;
11546879Sbostic static void onintr(), timeout(), dbg_signal();
11646879Sbostic static char *pskip();
11733945Srick extern char *optarg;
11833945Srick extern int optind;
11923725Sbloom char rflags[MAXFULLNAME];
12023590Sbloom #ifdef NOGETPEER
12117767Sralph u_long Hostnumber = 0;
12223590Sbloom #endif NOGETPEER
12313639Ssam
12413639Ssam strcpy(Progname, "uucico");
12513639Ssam
12626149Sbloom #ifdef BSD4_2
12733945Srick sigsetmask(0L); /* in case we inherit blocked signals */
12826149Sbloom #endif BSD4_2
12913639Ssam signal(SIGINT, onintr);
13013639Ssam signal(SIGHUP, onintr);
13113639Ssam signal(SIGQUIT, onintr);
13213639Ssam signal(SIGTERM, onintr);
13313639Ssam signal(SIGPIPE, onintr); /* 4.1a tcp-ip stupidity */
13436449Smarc signal(SIGUSR1, dbg_signal);
13513639Ssam ret = guinfo(getuid(), User, msg);
13613639Ssam strcpy(Loginuser, User);
13723590Sbloom uucpname(Myname);
13833945Srick if (ret == FAIL) {
13933945Srick syslog(LOG_ERR, "can't get uid");
14033945Srick cleanup(FAIL);
14133945Srick }
14213639Ssam
14325703Sbloom setbuf (stderr, CNULL);
14425703Sbloom
14525703Sbloom rflags[0] = '\0';
14613639Ssam umask(WFMASK);
14713639Ssam strcpy(Rmtname, Myname);
14813639Ssam Ifn = Ofn = -1;
14933945Srick while ((ret = getopt(argc, argv, "RLd:g:p:r:s:x:t:")) != EOF)
15033945Srick switch(ret){
15113639Ssam case 'd':
15233945Srick Spool = optarg;
15313639Ssam break;
15413639Ssam case 'g':
15518616Sralph case 'p':
15633945Srick MaxGrade = DefMaxGrade = *optarg;
15713639Ssam break;
15813639Ssam case 'r':
15933945Srick Role = atoi(optarg);
16013639Ssam break;
16117767Sralph case 'R':
16217767Sralph ReverseRole++;
16317767Sralph Role = MASTER;
16417767Sralph break;
16513639Ssam case 's':
16633945Srick strncpy(Rmtname, optarg, MAXBASENAME);
16723590Sbloom Rmtname[MAXBASENAME] = '\0';
16813639Ssam if (Rmtname[0] != '\0')
16913639Ssam onesys = 1;
17013639Ssam break;
17113639Ssam case 'x':
17233945Srick Debug = atoi(optarg);
17313639Ssam if (Debug <= 0)
17413639Ssam Debug = 1;
17533945Srick strcat(rflags, argv[optind-1]);
17613639Ssam break;
17718616Sralph case 't':
17833945Srick turntime = atoi(optarg)*60;/* minutes to seconds */
17918616Sralph break;
18017767Sralph case 'L': /* local calls only */
18117767Sralph LocalOnly++;
18217767Sralph break;
18323590Sbloom #ifdef NOGETPEER
18417767Sralph case 'h':
18517767Sralph Hostnumber = inet_addr(&argv[1][2]);
18617767Sralph break;
18723590Sbloom #endif NOGETPEER
18833945Srick case '?':
18913639Ssam default:
19033945Srick fprintf(stderr, "unknown flag %s (ignored)\n",
19133945Srick argv[optind-1]);
19213639Ssam break;
19313639Ssam }
19413639Ssam
19533945Srick while (optind < argc)
19633945Srick fprintf(stderr, "unknown argument %s (ignored)\n",
19733945Srick argv[optind++]);
19817767Sralph
19927069Sbloom if (Debug && Role == MASTER)
20027069Sbloom chkdebug();
20127069Sbloom
20234164Srick #ifdef SETPROCTITLE
20334164Srick /*
20434164Srick * Save start and extent of argv for setproctitle.
20534164Srick */
20634164Srick
20734164Srick Argv = argv;
20834164Srick LastArgv = argv[argc - 1] + strlen(argv[argc - 1]);
20934164Srick #endif SETPROCTITLE
21034164Srick
21125124Sbloom /* Try to run as uucp */
21217767Sralph setgid(getegid());
21317767Sralph setuid(geteuid());
21417767Sralph #ifdef TIOCNOTTY
21517767Sralph /*
21617767Sralph * detach uucico from controlling terminal
21717767Sralph * to defend against rlogind sending us a SIGKILL (!!!)
21817767Sralph */
21937930Sbostic if (Role == MASTER && (ret = open(_PATH_TTY, 2)) >= 0) {
22017767Sralph ioctl(ret, TIOCNOTTY, STBNULL);
22117767Sralph close(ret);
22217767Sralph }
22317767Sralph #endif TIOCNOTTY
22417767Sralph #ifdef BSD4_2
22525517Stef if (getpgrp(0) == 0) { /* We have no controlling terminal */
22617767Sralph setpgrp(0, getpid());
22717767Sralph }
22833945Srick #ifdef USE_SYSLOG
22933945Srick #ifdef BSD4_3
23033945Srick openlog("uucico", LOG_PID, LOG_UUCP);
23133945Srick #else /* !BSD4_3 */
23233945Srick openlog("uucico", LOG_PID);
23333945Srick #endif /* !BSD4_3 */
23433945Srick #endif /* USE_SYSLOG */
23517767Sralph #endif BSD4_2
23617767Sralph
23733945Srick #ifdef BSD4_3
23833945Srick unsetenv("TZ"); /* We don't want him resetting our time zone */
23933945Srick #endif /* !BSD4_3 */
24033945Srick
24133945Srick if (subchdir(Spool) < 0) {
24233945Srick syslog(LOG_ERR, "chdir(%s) failed: %m", Spool);
24333945Srick cleanup(FAIL);
24433945Srick }
24533945Srick
24613639Ssam strcpy(Wrkdir, Spool);
24713639Ssam
24825703Sbloom if (Debug) {
24925703Sbloom setdebug ((Role == SLAVE) ? DBG_TEMP : DBG_PERM);
25025703Sbloom if (Debug > 0)
25125703Sbloom logent ("Local Enabled", "DEBUG");
25225703Sbloom }
25325703Sbloom
25425703Sbloom /*
25525703Sbloom * First time through: If we're the slave, do initial checking.
25625703Sbloom */
25713639Ssam if (Role == SLAVE) {
25817767Sralph /* check for /etc/nologin */
25925124Sbloom if (access(NOLOGIN, 0) == 0) {
26017767Sralph logent(NOLOGIN, "UUCICO SHUTDOWN");
26123590Sbloom if (Debug > 4)
26217767Sralph logent("DEBUGGING", "continuing anyway");
26317767Sralph else
26417767Sralph cleanup(1);
26517767Sralph }
26625703Sbloom Ifn = 0;
26725703Sbloom Ofn = 1;
26817767Sralph #ifdef TCPIP
26917767Sralph /*
27017767Sralph * Determine if we are on TCPIP
27117767Sralph */
27233559Srick if (isatty(Ifn) == 0) {
27317767Sralph IsTcpIp = 1;
27417767Sralph DEBUG(4, "TCPIP connection -- ioctl-s disabled\n", CNULL);
27523590Sbloom } else
27623590Sbloom IsTcpIp = 0;
27717767Sralph #endif TCPIP
27813639Ssam /* initial handshake */
27913639Ssam onesys = 1;
28017767Sralph if (!IsTcpIp) {
28117767Sralph #ifdef USG
28225703Sbloom ret = ioctl(Ifn, TCGETA, &Savettyb);
28313639Ssam Savettyb.c_cflag = (Savettyb.c_cflag & ~CS8) | CS7;
28413639Ssam Savettyb.c_oflag |= OPOST;
28513639Ssam Savettyb.c_lflag |= (ISIG|ICANON|ECHO);
28617767Sralph #else !USG
28725703Sbloom ret = ioctl(Ifn, TIOCGETP, &Savettyb);
28813639Ssam Savettyb.sg_flags |= ECHO;
28913639Ssam Savettyb.sg_flags &= ~RAW;
29017767Sralph #endif !USG
29125703Sbloom ttyn = ttyname(Ifn);
29213639Ssam }
29313639Ssam fixmode(Ifn);
29425703Sbloom
29525703Sbloom /*
29625703Sbloom * Initial Message -- tell them we're here, and who we are.
29725703Sbloom */
29818616Sralph sprintf(msg, "here=%s", Myfullname);
29917767Sralph omsg('S', msg, Ofn);
30013639Ssam signal(SIGALRM, timeout);
30133559Srick alarm(IsTcpIp?MAXMSGTIME*4:MAXMSGTIME);
30213639Ssam if (setjmp(Sjbuf)) {
30313639Ssam /* timed out */
30417767Sralph if (!IsTcpIp) {
30517767Sralph #ifdef USG
30625703Sbloom ret = ioctl(Ifn, TCSETA, &Savettyb);
30725703Sbloom
30823590Sbloom #else !USG
30925703Sbloom ret = ioctl(Ifn, TIOCSETP, &Savettyb);
31023590Sbloom #endif !USG
31113639Ssam }
31217767Sralph cleanup(0);
31313639Ssam }
31413639Ssam for (;;) {
31513639Ssam ret = imsg(msg, Ifn);
31625703Sbloom if (ret != SUCCESS) {
31713639Ssam alarm(0);
31817767Sralph if (!IsTcpIp) {
31917767Sralph #ifdef USG
32025703Sbloom ret = ioctl(Ifn, TCSETA, &Savettyb);
32123590Sbloom #else !USG
32225703Sbloom ret = ioctl(Ifn, TIOCSETP, &Savettyb);
32323590Sbloom #endif !USG
32413639Ssam }
32517767Sralph cleanup(0);
32613639Ssam }
32713639Ssam if (msg[0] == 'S')
32813639Ssam break;
32913639Ssam }
33013639Ssam alarm(0);
33113639Ssam q = &msg[1];
33213639Ssam p = pskip(q);
33323590Sbloom strncpy(Rmtname, q, MAXBASENAME);
33423590Sbloom Rmtname[MAXBASENAME] = '\0';
33525703Sbloom
33625703Sbloom /*
33725703Sbloom * Now that we know who they are, give the audit file the right
33825703Sbloom * name.
33925703Sbloom */
34025703Sbloom setdebug (DBG_PERM);
34113639Ssam DEBUG(4, "sys-%s\n", Rmtname);
34223725Sbloom /* The versys will also do an alias on the incoming name */
34323725Sbloom if (versys(&Rmtname)) {
34433559Srick #ifdef NOSTRANGERS
34523725Sbloom /* If we don't know them, we won't talk to them... */
34633945Srick syslog(LOG_WARNING, "Unknown host: %s", Rmtname);
34723590Sbloom omsg('R', "You are unknown to me", Ofn);
34823590Sbloom cleanup(0);
34923725Sbloom #endif NOSTRANGERS
35023590Sbloom }
35117767Sralph #ifdef BSDTCP
35217767Sralph /* we must make sure they are really who they say they
35317767Sralph * are. We compare the hostnumber with the number in the hosts
35417767Sralph * table for the site they claim to be.
35517767Sralph */
35617767Sralph if (IsTcpIp) {
35717767Sralph struct hostent *hp;
35817767Sralph char *cpnt, *inet_ntoa();
35925703Sbloom int fromlen;
36017767Sralph struct sockaddr_in from;
36125124Sbloom extern char PhoneNumber[];
36217767Sralph
36323590Sbloom #ifdef NOGETPEER
36423590Sbloom from.sin_addr.s_addr = Hostnumber;
36523590Sbloom from.sin_family = AF_INET;
36623590Sbloom #else !NOGETPEER
36725703Sbloom fromlen = sizeof(from);
36846879Sbostic if (getpeername(Ifn,
36946879Sbostic (struct sockaddr *)&from, &fromlen) < 0) {
37017767Sralph logent(Rmtname, "NOT A TCP CONNECTION");
37117767Sralph omsg('R', "NOT TCP", Ofn);
37217767Sralph cleanup(0);
37317767Sralph }
37423590Sbloom #endif !NOGETPEER
37546879Sbostic hp = gethostbyaddr((char *)&from.sin_addr,
37617767Sralph sizeof (struct in_addr), from.sin_family);
37725703Sbloom if (hp == NULL) {
37817767Sralph /* security break or just old host table? */
37917767Sralph logent(Rmtname, "UNKNOWN IP-HOST Name =");
38017767Sralph cpnt = inet_ntoa(from.sin_addr),
38117767Sralph logent(cpnt, "UNKNOWN IP-HOST Number =");
38217767Sralph sprintf(wkpre, "%s/%s isn't in my host table",
38317767Sralph Rmtname, cpnt);
38417767Sralph omsg('R' ,wkpre ,Ofn);
38517767Sralph cleanup(0);
38617767Sralph }
38725703Sbloom if (Debug > 99)
38817767Sralph logent(Rmtname,"Request from IP-Host name =");
38925124Sbloom /*
39025124Sbloom * The following is to determine if the name given us by
39125124Sbloom * the Remote uucico matches any of the names
39217767Sralph * given its network number (remote machine) in our
39317767Sralph * host table.
39425124Sbloom * We could check the aliases, but that won't work in
39525124Sbloom * all cases (like if you are running the domain
39625124Sbloom * server, where you don't get any aliases). The only
39725124Sbloom * reliable way I can think of that works in ALL cases
39825124Sbloom * is too look up the site in L.sys and see if the
39925124Sbloom * sitename matches what we would call him if we
40025124Sbloom * originated the call.
40117767Sralph */
40225124Sbloom /* PhoneNumber contains the official network name of the host we are checking. (set in versys.c) */
40325124Sbloom if (sncncmp(PhoneNumber, hp->h_name, SYSNSIZE) == 0) {
40417767Sralph if (Debug > 99)
40517767Sralph logent(q,"Found in host Tables");
40625124Sbloom } else {
40725124Sbloom logent(hp->h_name, "FORGED HOSTNAME");
40825124Sbloom logent(inet_ntoa(from.sin_addr), "ORIGINATED AT");
40925124Sbloom logent(PhoneNumber, "SHOULD BE");
41025124Sbloom sprintf(wkpre, "You're not who you claim to be: %s != %s", hp->h_name, PhoneNumber);
41125124Sbloom omsg('R', wkpre, Ofn);
41225124Sbloom cleanup(0);
41317767Sralph }
41417767Sralph }
41517767Sralph #endif BSDTCP
41617767Sralph
41725703Sbloom if (mlock(Rmtname)) {
41813639Ssam omsg('R', "LCK", Ofn);
41913639Ssam cleanup(0);
42013639Ssam }
42113639Ssam else if (callback(Loginuser)) {
42213639Ssam signal(SIGINT, SIG_IGN);
42313639Ssam signal(SIGHUP, SIG_IGN);
42413639Ssam omsg('R', "CB", Ofn);
42513639Ssam logent("CALLBACK", "REQUIRED");
42613639Ssam /* set up for call back */
42717767Sralph systat(Rmtname, SS_CALLBACK, "CALLING BACK");
42813639Ssam gename(CMDPRE, Rmtname, 'C', file);
42913639Ssam close(creat(subfile(file), 0666));
43013639Ssam xuucico(Rmtname);
43113639Ssam cleanup(0);
43213639Ssam }
43313639Ssam seq = 0;
43413639Ssam while (*p == '-') {
43513639Ssam q = pskip(p);
43613639Ssam switch(*(++p)) {
43713639Ssam case 'x':
43825703Sbloom if (Debug == 0) {
43925703Sbloom Debug = atoi(++p);
44025703Sbloom if (Debug <= 0)
44125703Sbloom Debug = 1;
44225703Sbloom setdebug(DBG_PERM);
44325703Sbloom if (Debug > 0)
44425703Sbloom logent("Remote Enabled", "DEBUG");
44525703Sbloom } else {
44625703Sbloom DEBUG(1, "Remote debug request ignored\n",
44725703Sbloom CNULL);
44825703Sbloom }
44913639Ssam break;
45013639Ssam case 'Q':
45113639Ssam seq = atoi(++p);
45213639Ssam break;
45318616Sralph case 'p':
45418616Sralph MaxGrade = DefMaxGrade = *++p;
45518616Sralph DEBUG(4, "MaxGrade set to %c\n", MaxGrade);
45618616Sralph break;
45723590Sbloom case 'v':
45823590Sbloom if (strncmp(p, "grade", 5) == 0) {
45923590Sbloom p += 6;
46023590Sbloom MaxGrade = DefMaxGrade = *p++;
46123590Sbloom DEBUG(4, "MaxGrade set to %c\n", MaxGrade);
46223590Sbloom }
46323590Sbloom break;
46413639Ssam default:
46513639Ssam break;
46613639Ssam }
46713639Ssam p = q;
46813639Ssam }
46934164Srick setproctitle("%s: startup", Rmtname);
47013639Ssam if (callok(Rmtname) == SS_BADSEQ) {
47113639Ssam logent("BADSEQ", "PREVIOUS");
47213639Ssam omsg('R', "BADSEQ", Ofn);
47313639Ssam cleanup(0);
47413639Ssam }
47517767Sralph #ifdef GNXSEQ
47613639Ssam if ((ret = gnxseq(Rmtname)) == seq) {
47713639Ssam omsg('R', "OK", Ofn);
47813639Ssam cmtseq();
47917767Sralph } else {
48017767Sralph #else !GNXSEQ
48117767Sralph if (seq == 0)
48217767Sralph omsg('R', "OK", Ofn);
48313639Ssam else {
48417767Sralph #endif !GNXSEQ
48513639Ssam systat(Rmtname, Stattype[7], Stattext[7]);
48623590Sbloom logent("BAD SEQ", "FAILED HANDSHAKE");
48717767Sralph #ifdef GNXSEQ
48813639Ssam ulkseq();
48917767Sralph #endif GNXSEQ
49013639Ssam omsg('R', "BADSEQ", Ofn);
49113639Ssam cleanup(0);
49213639Ssam }
49313639Ssam if (ttyn != NULL)
49413639Ssam chmod(ttyn, 0600);
49513639Ssam }
49617767Sralph
49713639Ssam loop:
49817767Sralph if(setjmp(Pipebuf)) { /* come here on SIGPIPE */
49917767Sralph clsacu();
50034164Srick logcls();
50117767Sralph close(Ofn);
50217767Sralph close(Ifn);
50317767Sralph Ifn = Ofn = -1;
50417767Sralph rmlock(CNULL);
50517767Sralph sleep(3);
50617767Sralph }
50713639Ssam if (!onesys) {
50833559Srick do_connect_accounting();
50933945Srick #ifdef DIALINOUT
51033945Srick /* reenable logins on dialout */
51133945Srick reenable();
51233945Srick #endif DIALINOUT
51333559Srick StartTime = 0;
51434164Srick setproctitle("looking for work");
51513639Ssam ret = gnsys(Rmtname, Spool, CMDPRE);
51634164Srick setproctitle("%s: startup", Rmtname);
51725703Sbloom setdebug(DBG_PERM);
51813639Ssam if (ret == FAIL)
51913639Ssam cleanup(100);
52033559Srick else if (ret == SUCCESS)
52113639Ssam cleanup(0);
52234164Srick logcls();
52317767Sralph } else if (Role == MASTER && callok(Rmtname) != 0) {
52413639Ssam logent("SYSTEM STATUS", "CAN NOT CALL");
52513639Ssam cleanup(0);
52613639Ssam }
52713639Ssam
52823590Sbloom sprintf(wkpre, "%c.%.*s", CMDPRE, SYSNSIZE, Rmtname);
52933559Srick StartTime = 0;
53033559Srick Bytes_Sent = Bytes_Received = 0L;
53113639Ssam
53217767Sralph signal(SIGINT, SIG_IGN);
53317767Sralph signal(SIGQUIT, SIG_IGN);
53413639Ssam if (Role == MASTER) {
53533559Srick extern char LineType[];
53617767Sralph /* check for /etc/nologin */
53725124Sbloom if (access(NOLOGIN, 0) == 0) {
53817767Sralph logent(NOLOGIN, "UUCICO SHUTDOWN");
53923590Sbloom if (Debug > 4)
54017767Sralph logent("DEBUGGING", "continuing anyway");
54117767Sralph else
54217767Sralph cleanup(1);
54317767Sralph }
54413639Ssam /* master part */
54513639Ssam signal(SIGHUP, SIG_IGN);
54613639Ssam if (Ifn != -1 && Role == MASTER) {
54713639Ssam write(Ofn, EOTMSG, strlen(EOTMSG));
54813639Ssam clsacu();
54913639Ssam close(Ofn);
55013639Ssam close(Ifn);
55113639Ssam Ifn = Ofn = -1;
55213639Ssam rmlock(CNULL);
55313639Ssam sleep(3);
55413639Ssam }
55525124Sbloom if (mlock(Rmtname) != SUCCESS) {
55633559Srick DEBUG(1, "LOCKED: call to %s\n", Rmtname);
55717767Sralph US_SST(us_s_lock);
55813639Ssam goto next;
55913639Ssam }
56034164Srick setproctitle("%s: starting call", Rmtname);
56113639Ssam Ofn = Ifn = conn(Rmtname);
56234164Srick sprintf(msg, "(call to %s via %s)", Rmtname, LineType);
56313639Ssam if (Ofn < 0) {
56417767Sralph if (Ofn != CF_TIME)
56517767Sralph logent(msg, _FAILED);
56617767Sralph /* avoid excessive 'wrong time' info */
56723590Sbloom if (Stattype[-Ofn] != SS_WRONGTIME){
56817767Sralph systat(Rmtname, Stattype[-Ofn], Stattext[-Ofn]);
56917767Sralph US_SST(-Ofn);
57017767Sralph UB_SST(-Ofn);
57117767Sralph }
57213639Ssam goto next;
57317767Sralph } else {
57413639Ssam logent(msg, "SUCCEEDED");
57517767Sralph US_SST(us_s_cok);
57617767Sralph UB_SST(ub_ok);
57713639Ssam }
57833559Srick InitialRole = MASTER;
57917767Sralph #ifdef TCPIP
58017767Sralph /*
58117767Sralph * Determine if we are on TCPIP
58217767Sralph */
58325703Sbloom if (isatty(Ifn) == 0) {
58417767Sralph IsTcpIp = 1;
58517767Sralph DEBUG(4, "TCPIP connection -- ioctl-s disabled\n", CNULL);
58623590Sbloom } else
58723590Sbloom IsTcpIp = 0;
58817767Sralph #endif
58917767Sralph
59013639Ssam if (setjmp(Sjbuf))
59113639Ssam goto next;
59213639Ssam signal(SIGALRM, timeout);
59333559Srick alarm(IsTcpIp?MAXMSGTIME*4:MAXMSGTIME*2);
59413639Ssam for (;;) {
59513639Ssam ret = imsg(msg, Ifn);
59633559Srick if (ret != SUCCESS) {
59713639Ssam alarm(0);
59833559Srick DEBUG(4,"\nimsg failed: errno %d\n", errno);
59917767Sralph logent("imsg 1", _FAILED);
60017767Sralph goto Failure;
60113639Ssam }
60213639Ssam if (msg[0] == 'S')
60313639Ssam break;
60413639Ssam }
60533559Srick alarm(IsTcpIp?MAXMSGTIME*4:MAXMSGTIME);
60617767Sralph #ifdef GNXSEQ
60713639Ssam seq = gnxseq(Rmtname);
60817767Sralph #else !GNXSEQ
60917767Sralph seq = 0;
61017767Sralph #endif !GNXSEQ
61118616Sralph if (MaxGrade != '\177') {
61223590Sbloom DEBUG(2, "Max Grade this transfer is %c\n", MaxGrade);
61325963Sbloom sprintf(msg, "%s -Q%d -p%c -vgrade=%c %s",
61425963Sbloom Myname, seq, MaxGrade, MaxGrade, rflags);
61525963Sbloom } else
61625963Sbloom sprintf(msg, "%s -Q%d %s", Myname, seq, rflags);
61713639Ssam omsg('S', msg, Ofn);
61813639Ssam for (;;) {
61913639Ssam ret = imsg(msg, Ifn);
62013639Ssam DEBUG(4, "msg-%s\n", msg);
62117767Sralph if (ret != SUCCESS) {
62213639Ssam alarm(0);
62317767Sralph #ifdef GNXSEQ
62413639Ssam ulkseq();
62517767Sralph #endif GNXSEQ
62617767Sralph logent("imsg 2", _FAILED);
62717767Sralph goto Failure;
62813639Ssam }
62913639Ssam if (msg[0] == 'R')
63013639Ssam break;
63113639Ssam }
63213639Ssam alarm(0);
63313639Ssam if (msg[1] == 'B') {
63413639Ssam /* bad sequence */
63523590Sbloom logent("BAD SEQ", "FAILED HANDSHAKE");
63617767Sralph US_SST(us_s_hand);
63717767Sralph systat(Rmtname, SS_BADSEQ, Stattext[SS_BADSEQ]);
63817767Sralph #ifdef GNXSEQ
63913639Ssam ulkseq();
64017767Sralph #endif GNXSEQ
64113639Ssam goto next;
64213639Ssam }
64313639Ssam if (strcmp(&msg[1], "OK") != SAME) {
64423590Sbloom logent(&msg[1], "FAILED HANDSHAKE");
64517767Sralph US_SST(us_s_hand);
64617767Sralph #ifdef GNXSEQ
64713639Ssam ulkseq();
64817767Sralph #endif GNXSEQ
64917767Sralph systat(Rmtname, SS_INPROGRESS,
65017767Sralph strcmp(&msg[1], "CB") == SAME?
65123590Sbloom "AWAITING CALLBACK": "FAILED HANDSHAKE");
65213639Ssam goto next;
65313639Ssam }
65417767Sralph #ifdef GNXSEQ
65513639Ssam cmtseq();
65617767Sralph #endif GNXSEQ
65713639Ssam }
65817767Sralph DEBUG(1, "Rmtname %s, ", Rmtname);
65913639Ssam DEBUG(1, "Role %s, ", Role ? "MASTER" : "SLAVE");
66013639Ssam DEBUG(1, "Ifn - %d, ", Ifn);
66113639Ssam DEBUG(1, "Loginuser - %s\n", Loginuser);
66234164Srick setproctitle("%s: %s", Rmtname, Role ? "MASTER" : "SLAVE");
66313639Ssam
66425703Sbloom ttyn = ttyname(Ifn);
66525703Sbloom
66633559Srick alarm(IsTcpIp?MAXMSGTIME*4:MAXMSGTIME);
66718616Sralph if (ret=setjmp(Sjbuf))
66813639Ssam goto Failure;
66913639Ssam ret = startup(Role);
67013639Ssam alarm(0);
67113639Ssam if (ret != SUCCESS) {
67234164Srick logent("(startup)", _FAILED);
67313639Ssam Failure:
67417767Sralph US_SST(us_s_start);
67518616Sralph systat(Rmtname, SS_FAIL, ret > 0 ? "CONVERSATION FAILED" :
67618616Sralph "STARTUP FAILED");
67713639Ssam goto next;
67817767Sralph } else {
67933559Srick char smsg[BUFSIZ], gmsg[10], pmsg[20], bpsmsg[20];
68033559Srick extern char UsingProtocol;
68133559Srick extern int linebaudrate;
68233559Srick if (ttyn != NULL)
68333559Srick sprintf(bpsmsg, " %s %d bps", &ttyn[5], linebaudrate);
68433559Srick else
68533559Srick bpsmsg[0] = '\0';
68633559Srick if (UsingProtocol != 'g')
68733559Srick sprintf(pmsg, " %c protocol", UsingProtocol);
68833559Srick else
68933559Srick pmsg[0] = '\0';
69033559Srick if (MaxGrade != '\177')
69133559Srick sprintf(gmsg, " grade %c", MaxGrade);
69233559Srick else
69333559Srick gmsg[0] = '\0';
69434164Srick sprintf(smsg, "(startup%s%s%s)", bpsmsg, pmsg, gmsg);
69533559Srick logent(smsg, "OK");
69617767Sralph US_SST(us_s_gress);
69733559Srick StartTime = Now.time;
69813639Ssam systat(Rmtname, SS_INPROGRESS, "TALKING");
69913639Ssam ret = cntrl(Role, wkpre);
70013639Ssam DEBUG(1, "cntrl - %d\n", ret);
70113639Ssam signal(SIGINT, SIG_IGN);
70213639Ssam signal(SIGHUP, SIG_IGN);
70313639Ssam signal(SIGALRM, timeout);
70434164Srick sprintf(smsg, "(conversation complete %ld sent %ld received)",
70533559Srick Bytes_Sent, Bytes_Received);
70617767Sralph if (ret == SUCCESS) {
70733559Srick logent(smsg, "OK");
70817767Sralph US_SST(us_s_ok);
70913639Ssam rmstat(Rmtname);
71013639Ssam
71117767Sralph } else {
71233559Srick logent(smsg, _FAILED);
71317767Sralph US_SST(us_s_cf);
71417767Sralph systat(Rmtname, SS_FAIL, "CONVERSATION FAILED");
71513639Ssam }
71633559Srick alarm(IsTcpIp?MAXMSGTIME*4:MAXMSGTIME);
71713639Ssam DEBUG(4, "send OO %d,", ret);
71813639Ssam if (!setjmp(Sjbuf)) {
71913639Ssam for (;;) {
72013639Ssam omsg('O', "OOOOO", Ofn);
72113639Ssam ret = imsg(msg, Ifn);
72213639Ssam if (ret != 0)
72313639Ssam break;
72413639Ssam if (msg[0] == 'O')
72513639Ssam break;
72613639Ssam }
72713639Ssam }
72813639Ssam alarm(0);
72917767Sralph clsacu();
73017767Sralph rmlock(CNULL);
73133559Srick
73213639Ssam }
73313639Ssam next:
73413639Ssam if (!onesys) {
73513639Ssam goto loop;
73613639Ssam }
73713639Ssam cleanup(0);
73813639Ssam }
73913639Ssam
74017767Sralph #ifndef USG
74113639Ssam struct sgttyb Hupvec;
74213639Ssam #endif
74313639Ssam
74425703Sbloom /*
74525703Sbloom * cleanup and exit with "code" status
74613639Ssam */
cleanup(code)74713639Ssam cleanup(code)
74813639Ssam register int code;
74913639Ssam {
75013639Ssam signal(SIGINT, SIG_IGN);
75113639Ssam signal(SIGHUP, SIG_IGN);
75213639Ssam rmlock(CNULL);
75325703Sbloom sleep(5); /* Wait for any pending output */
75413639Ssam clsacu();
75513639Ssam logcls();
75613639Ssam if (Role == SLAVE) {
75717767Sralph if (!IsTcpIp) {
75817767Sralph #ifdef USG
75913639Ssam Savettyb.c_cflag |= HUPCL;
76023590Sbloom (void) ioctl(0, TCSETA, &Savettyb);
76117767Sralph #else !USG
76223590Sbloom (void) ioctl(0, TIOCHPCL, STBNULL);
76318616Sralph #ifdef TIOCSDTR
76423590Sbloom (void) ioctl(0, TIOCCDTR, STBNULL);
76518616Sralph sleep(2);
76623590Sbloom (void) ioctl(0, TIOCSDTR, STBNULL);
76718616Sralph #else !TIOCSDTR
76823590Sbloom (void) ioctl(0, TIOCGETP, &Hupvec);
76913639Ssam Hupvec.sg_ispeed = B0;
77013639Ssam Hupvec.sg_ospeed = B0;
77123590Sbloom (void) ioctl(0, TIOCSETP, &Hupvec);
77225703Sbloom #endif !TIOCSDTR
77313639Ssam sleep(2);
77423590Sbloom (void) ioctl(0, TIOCSETP, &Savettyb);
77517767Sralph /* make *sure* exclusive access is off */
77623590Sbloom (void) ioctl(0, TIOCNXCL, STBNULL);
77717767Sralph #endif !USG
77813639Ssam }
77913639Ssam if (ttyn != NULL)
78013639Ssam chmod(ttyn, 0600);
78113639Ssam }
78213639Ssam if (Ofn != -1) {
78313639Ssam if (Role == MASTER)
78413639Ssam write(Ofn, EOTMSG, strlen(EOTMSG));
78513639Ssam close(Ifn);
78613639Ssam close(Ofn);
78713639Ssam }
78818616Sralph #ifdef DIALINOUT
78918616Sralph /* reenable logins on dialout */
79018616Sralph reenable();
79118616Sralph #endif DIALINOUT
79213639Ssam if (code == 0)
79313639Ssam xuuxqt();
79417767Sralph else
79517767Sralph DEBUG(1, "exit code %d\n", code);
79625703Sbloom setdebug (DBG_CLEAN);
79733559Srick do_connect_accounting();
79813639Ssam exit(code);
79913639Ssam }
80013639Ssam
do_connect_accounting()80133559Srick do_connect_accounting()
80233559Srick {
80333945Srick #ifdef DO_CONNECT_ACCOUNTING
80433559Srick register FILE *fp;
80533559Srick struct tm *localtime();
80633559Srick register struct tm *tm;
80733559Srick int flags;
80833559Srick
80933559Srick if (StartTime == 0)
81033559Srick return;
81133559Srick
81233945Srick fp = fopen(DO_CONNECT_ACCOUNTING, "a");
81333945Srick if (fp == NULL) {
81433945Srick syslog(LOG_ALERT, "fopen(%s) failed: %m",DO_CONNECT_ACCOUNTING);
81533945Srick cleanup(FAIL);
81633945Srick }
81733559Srick
81833559Srick tm = localtime(&StartTime);
81933559Srick #ifdef F_SETFL
82033559Srick flags = fcntl(fileno(fp), F_GETFL, 0);
82133559Srick fcntl(fileno(fp), F_SETFL, flags|O_APPEND);
82233559Srick #endif
82333559Srick #ifdef USG
82433559Srick fprintf(fp,"%s %d %d%.2d%.2d %.2d%.2d %d %ld %s %ld %ld\n",
82533559Srick #else /* V7 */
82633559Srick fprintf(fp,"%s %d %d%02d%02d %02d%02d %d %ld %s %ld %ld\n",
82733559Srick #endif /* V7 */
82833559Srick Rmtname, InitialRole, tm->tm_year, tm->tm_mon + 1,
82933559Srick tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_wday,
83033559Srick (Now.time - StartTime + 59) / 60,
83133559Srick ttyn == NULL ? "ttyp0" : &ttyn[5],
83233559Srick Bytes_Sent, Bytes_Received);
83333559Srick fclose(fp);
83433559Srick #endif /* DO_CONNECT_ACCOUNTING */
83533559Srick }
83633559Srick
83725703Sbloom /*
83825703Sbloom * on interrupt - remove locks and exit
83913639Ssam */
84013639Ssam
84146879Sbostic static void
onintr(inter)84213639Ssam onintr(inter)
84313639Ssam register int inter;
84413639Ssam {
84533559Srick char str[BUFSIZ];
84613639Ssam signal(inter, SIG_IGN);
84734164Srick sprintf(str, "(SIGNAL %d)", inter);
84813639Ssam logent(str, "CAUGHT");
84917767Sralph US_SST(us_s_intr);
85023590Sbloom if (*Rmtname && strncmp(Rmtname, Myname, MAXBASENAME))
85117767Sralph systat(Rmtname, SS_FAIL, str);
85234164Srick sprintf(str, "(conversation complete %ld sent %ld received)",
85333559Srick Bytes_Sent, Bytes_Received);
85433559Srick logent(str, _FAILED);
85517767Sralph if (inter == SIGPIPE && !onesys)
85617767Sralph longjmp(Pipebuf, 1);
85713639Ssam cleanup(inter);
85813639Ssam }
85913639Ssam
86013639Ssam /*
86113639Ssam * Catch a special signal
86236449Smarc * (SIGUSR1), and toggle debugging between 0 and 30.
86313639Ssam * Handy for looking in on long running uucicos.
86413639Ssam */
86546879Sbostic static void
dbg_signal()86625703Sbloom dbg_signal()
86713639Ssam {
86825703Sbloom Debug = (Debug == 0) ? 30 : 0;
86925703Sbloom setdebug(DBG_PERM);
87025703Sbloom if (Debug > 0)
87125703Sbloom logent("Signal Enabled", "DEBUG");
87225703Sbloom }
87317767Sralph
87425703Sbloom
87525703Sbloom /*
87625703Sbloom * Check debugging requests, and open RMTDEBUG audit file if necessary. If an
87725703Sbloom * audit file is needed, the parm argument indicates how to create the file:
87825703Sbloom *
87925703Sbloom * DBG_TEMP - Open a temporary file, with filename = RMTDEBUG/pid.
88025703Sbloom * DBG_PERM - Open a permanent audit file, filename = RMTDEBUG/Rmtname.
88125703Sbloom * If a temp file already exists, it is mv'ed to be permanent.
88225703Sbloom * DBG_CLEAN - Cleanup; unlink temp files.
88325703Sbloom *
88425703Sbloom * Restrictions - this code can only cope with one open debug file at a time.
88525703Sbloom * Each call creates a new file; if an old one of the same name exists it will
88625703Sbloom * be overwritten.
88725703Sbloom */
setdebug(parm)88825703Sbloom setdebug(parm)
88925703Sbloom int parm;
89025703Sbloom {
89125703Sbloom char buf[BUFSIZ]; /* Buffer for building filenames */
89225703Sbloom static char *temp = NULL; /* Ptr to temporary file name */
89325703Sbloom static int auditopen = 0; /* Set to 1 when we open a file */
89425703Sbloom struct stat stbuf; /* File status buffer */
89525703Sbloom
89625703Sbloom /*
89725703Sbloom * If movement or cleanup of a temp file is indicated, we do it no
89825703Sbloom * matter what.
89925703Sbloom */
90025703Sbloom if (temp != CNULL && parm == DBG_PERM) {
90125703Sbloom sprintf(buf, "%s/%s", RMTDEBUG, Rmtname);
90225703Sbloom unlink(buf);
90325703Sbloom if (link(temp, buf) != 0) {
90423590Sbloom Debug = 0;
90533945Srick syslog(LOG_ERR, "RMTDEBUG link(%s,%s) failed: %m",
90633945Srick temp, buf);
90733945Srick cleanup(FAIL);
90825703Sbloom }
90925703Sbloom parm = DBG_CLEAN;
91023590Sbloom }
91125703Sbloom if (parm == DBG_CLEAN) {
91225703Sbloom if (temp != CNULL) {
91325703Sbloom unlink(temp);
91425703Sbloom free(temp);
91525703Sbloom temp = CNULL;
91625703Sbloom }
91725703Sbloom return;
91825703Sbloom }
91925703Sbloom
92025703Sbloom if (Debug == 0)
92125703Sbloom return; /* Gotta be in debug to come here. */
92225703Sbloom
92325703Sbloom /*
92425703Sbloom * If we haven't opened a file already, we can just return if it's
92525703Sbloom * alright to use the stderr we came in with. We can if:
92625703Sbloom *
92725703Sbloom * Role == MASTER, and Stderr is a regular file, a TTY or a pipe.
92825703Sbloom *
92925703Sbloom * Caution: Detecting when stderr is a pipe is tricky, because the 4.2
93025703Sbloom * man page for fstat(2) disagrees with reality, and System V leaves it
93125703Sbloom * undefined, which means different implementations act differently.
93225703Sbloom */
93325703Sbloom if (!auditopen && Role == MASTER) {
93425703Sbloom if (isatty(fileno(stderr)))
93525703Sbloom return;
93625703Sbloom else if (fstat(fileno(stderr), &stbuf) == 0) {
93725703Sbloom #ifdef USG
93825703Sbloom /* Is Regular File or Fifo */
93925703Sbloom if ((stbuf.st_mode & 0060000) == 0)
94025703Sbloom return;
94125703Sbloom #else !USG
94217767Sralph #ifdef BSD4_2
94325703Sbloom /* Is Regular File */
94425703Sbloom if ((stbuf.st_mode & S_IFMT) == S_IFREG ||
94525703Sbloom stbuf.st_mode == 0) /* Is a pipe */
94625703Sbloom return;
94725703Sbloom #else !BSD4_2
94825703Sbloom /* Is Regular File or Pipe */
94925703Sbloom if ((stbuf.st_mode & S_IFMT) == S_IFREG)
95025703Sbloom return;
95125703Sbloom #endif BSD4_2
95225703Sbloom #endif USG
95325703Sbloom }
95417767Sralph }
95513639Ssam
95625703Sbloom /*
95725703Sbloom * We need RMTDEBUG directory to do auditing. If the file doesn't exist,
95825703Sbloom * then we forget about debugging; if it exists but has improper owner-
95925703Sbloom * ship or modes, we gripe about it in ERRLOG.
96025703Sbloom */
96125703Sbloom if (stat(RMTDEBUG, &stbuf) != SUCCESS) {
96225703Sbloom Debug = 0;
96325703Sbloom return;
96425703Sbloom }
96525703Sbloom if ((geteuid() != stbuf.st_uid) || /* We must own it */
96625703Sbloom ((stbuf.st_mode & 0170700) != 040700)) { /* Directory, rwx */
96725703Sbloom Debug = 0;
96833945Srick syslog(LOG_ERR, "%s: invalid directory mode: %o", RMTDEBUG,
96933945Srick stbuf.st_mode);
97025703Sbloom return;
97125703Sbloom }
97213639Ssam
97325703Sbloom if (parm == DBG_TEMP) {
97425703Sbloom sprintf(buf, "%s/%d", RMTDEBUG, getpid());
97525703Sbloom temp = malloc(strlen (buf) + 1);
97625703Sbloom if (temp == CNULL) {
97725703Sbloom Debug = 0;
97833945Srick syslog(LOG_ERR, "RMTDEBUG malloc failed: %m");
97933945Srick cleanup(FAIL);
98025703Sbloom }
98125703Sbloom strcpy(temp, buf);
98225703Sbloom } else
98325703Sbloom sprintf(buf, "%s/%s", RMTDEBUG, Rmtname);
98413639Ssam
98525703Sbloom unlink(buf);
98625703Sbloom if (freopen(buf, "w", stderr) != stderr) {
98725703Sbloom Debug = 0;
98833945Srick syslog(LOG_ERR, "RMTDEBUG freopen(%s) failed: %m", buf);
98933945Srick cleanup(FAIL);
99025703Sbloom }
99125703Sbloom setbuf(stderr, CNULL);
99225703Sbloom auditopen = 1;
99313639Ssam }
99413639Ssam
99523590Sbloom /*
99625703Sbloom * catch SIGALRM routine
99713639Ssam */
99846879Sbostic static void
timeout()99913639Ssam timeout()
100013639Ssam {
100123590Sbloom extern int HaveSentHup;
100223590Sbloom if (!HaveSentHup) {
100323590Sbloom logent(Rmtname, "TIMEOUT");
100423590Sbloom if (*Rmtname && strncmp(Rmtname, Myname, MAXBASENAME)) {
100523590Sbloom US_SST(us_s_tmot);
100623590Sbloom systat(Rmtname, SS_FAIL, "TIMEOUT");
100723590Sbloom }
100817767Sralph }
100913639Ssam longjmp(Sjbuf, 1);
101013639Ssam }
101113639Ssam
101213639Ssam static char *
pskip(p)101313639Ssam pskip(p)
101413639Ssam register char *p;
101513639Ssam {
101617767Sralph while(*p && *p != ' ')
101713639Ssam ++p;
101823590Sbloom while(*p && *p == ' ')
101917767Sralph *p++ = 0;
102017767Sralph return p;
102113639Ssam }
102234164Srick
102334164Srick /*
102434164Srick * clobber argv so ps will show what we're doing.
102534164Srick * stolen from sendmail
102634164Srick */
102734164Srick /*VARARGS1*/
setproctitle(fmt,a,b,c)102834164Srick setproctitle(fmt, a, b, c)
102934164Srick char *fmt;
103034164Srick {
103134164Srick #ifdef SETPROCTITLE
103234164Srick register char *p;
103334164Srick register int i;
103434164Srick extern char **Argv;
103534164Srick extern char *LastArgv;
103634164Srick char buf[BUFSIZ];
103734164Srick
103834164Srick (void) sprintf(buf, fmt, a, b, c);
103934164Srick
104034164Srick /* make ps print "(sendmail)" */
104134164Srick p = Argv[0];
104234164Srick *p++ = '-';
104334164Srick
104434164Srick i = strlen(buf);
104534164Srick if (i > LastArgv - p - 2) {
104634164Srick i = LastArgv - p - 2;
104734164Srick buf[i] = '\0';
104834164Srick }
104934164Srick (void) strcpy(p, buf);
105034164Srick p += i;
105134164Srick while (p < LastArgv)
105234164Srick *p++ = ' ';
105334164Srick #endif SETPROCTITLE
105434164Srick }
1055