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
813640Ssam #ifndef lint
9*62391Sbostic static char sccsid[] = "@(#)cntrl.c 8.1 (Berkeley) 06/06/93";
1048664Sbostic #endif /* not lint */
1113640Ssam
1213640Ssam #include "uucp.h"
1313640Ssam #include <sys/stat.h>
1417832Sralph #include "uust.h"
1513640Ssam
1617832Sralph extern int errno;
1718617Sralph extern int turntime;
1818617Sralph int willturn;
1923591Sbloom int HaveSentHup = 0;
2013640Ssam
2113640Ssam struct Proto {
2213640Ssam char P_id;
2313640Ssam int (*P_turnon)();
2413640Ssam int (*P_rdmsg)();
2513640Ssam int (*P_wrmsg)();
2613640Ssam int (*P_rddata)();
2713640Ssam int (*P_wrdata)();
2813640Ssam int (*P_turnoff)();
2913640Ssam };
3013640Ssam
3113640Ssam extern int gturnon(), gturnoff();
3213640Ssam extern int grdmsg(), grddata();
3313640Ssam extern int gwrmsg(), gwrdata();
3423591Sbloom extern int imsg(), omsg(), nullf();
3523591Sbloom #ifdef TCPIP
3617832Sralph extern int twrmsg(), trdmsg();
3717832Sralph extern int twrdata(), trddata();
3823591Sbloom #endif TCPIP
3917832Sralph #ifdef PAD
4017832Sralph extern int fturnon(), fturnoff();
4117832Sralph extern int frdmsg(), frddata();
4217832Sralph extern int fwrmsg(), fwrdata();
4317832Sralph #endif PAD
4413640Ssam
4513640Ssam struct Proto Ptbl[]={
4623591Sbloom #ifdef TCPIP
4723591Sbloom 't', nullf, trdmsg, twrmsg, trddata, twrdata, nullf,
4823591Sbloom #endif TCPIP
4917832Sralph #ifdef PAD
5017832Sralph 'f', fturnon, frdmsg, fwrmsg, frddata, fwrdata, fturnoff,
5117832Sralph #endif PAD
5213640Ssam 'g', gturnon, grdmsg, gwrmsg, grddata, gwrdata, gturnoff,
5313640Ssam '\0'
5413640Ssam };
5513640Ssam
5617832Sralph int (*Imsg)() = imsg, (*Omsg)() = omsg;
5713640Ssam
5813640Ssam int (*Rdmsg)()=imsg, (*Rddata)();
5913640Ssam int (*Wrmsg)()=omsg, (*Wrdata)();
6023591Sbloom int (*Turnon)()=nullf, (*Turnoff)() = nullf;
6113640Ssam
6225125Sbloom struct timeb Now, LastTurned, LastCheckedNoLogin;
6313640Ssam
6417832Sralph static char *YES = "Y";
6517832Sralph static char *NO = "N";
6613640Ssam
6718617Sralph int TransferSucceeded = 1;
6818617Sralph
6913640Ssam /* failure messages */
7013640Ssam #define EM_MAX 6
7113640Ssam #define EM_LOCACC "N1" /* local access to file denied */
7213640Ssam #define EM_RMTACC "N2" /* remote access to file/path denied */
7313640Ssam #define EM_BADUUCP "N3" /* a bad uucp command was generated */
7413640Ssam #define EM_NOTMP "N4" /* remote error - can't create temp */
7513640Ssam #define EM_RMTCP "N5" /* can't copy to remote directory - file in public */
7613640Ssam #define EM_LOCCP "N6" /* can't copy on local system */
7713640Ssam
7813640Ssam char *Em_msg[] = {
7913640Ssam "COPY FAILED (reason not given by remote)",
8013640Ssam "local access to file denied",
8113640Ssam "remote access to path/file denied",
8213640Ssam "system error - bad uucp command generated",
8313640Ssam "remote system can't create temp file",
8413640Ssam "can't copy to file/directory - file left in PUBDIR/user/file",
8517832Sralph "can't copy to file/directory on local system - file left in PUBDIR/user/file"
8613640Ssam };
8713640Ssam
8813640Ssam
8913640Ssam #define XUUCP 'X' /* execute uucp (string) */
9013640Ssam #define SLTPTCL 'P' /* select protocol (string) */
9113640Ssam #define USEPTCL 'U' /* use protocol (character) */
9213640Ssam #define RCVFILE 'R' /* receive file (string) */
9313640Ssam #define SNDFILE 'S' /* send file (string) */
9413640Ssam #define RQSTCMPT 'C' /* request complete (string - yes | no) */
9513640Ssam #define HUP 'H' /* ready to hangup (string - yes | no) */
9613640Ssam #define RESET 'X' /* reset line modes */
9713640Ssam
9813640Ssam #define W_TYPE wrkvec[0]
9913640Ssam #define W_FILE1 wrkvec[1]
10013640Ssam #define W_FILE2 wrkvec[2]
10113640Ssam #define W_USER wrkvec[3]
10213640Ssam #define W_OPTNS wrkvec[4]
10313640Ssam #define W_DFILE wrkvec[5]
10413640Ssam #define W_MODE wrkvec[6]
10513640Ssam #define W_NUSER wrkvec[7]
10613640Ssam
10717832Sralph #define XFRRATE 35000L
10817832Sralph #define RMESG(m, s, n) if (rmesg(m, s, n) != 0) {(*Turnoff)(); return FAIL;} else
10917832Sralph #define RAMESG(s, n) if (rmesg('\0', s, n) != 0) {(*Turnoff)(); return FAIL;} else
11017832Sralph #define WMESG(m, s) if(wmesg(m, s) != 0) {(*Turnoff)(); return FAIL;} else
11113640Ssam
11213640Ssam char Wfile[MAXFULLNAME] = {'\0'};
11313640Ssam char Dfile[MAXFULLNAME];
11413640Ssam
11513640Ssam /*
11613640Ssam * To avoid a huge backlog of X. files, start uuxqt every so often.
11713640Ssam */
11813640Ssam static int nXfiles = 0; /* number of X files since last uuxqt start */
11917832Sralph static char send_or_receive;
12017832Sralph struct stat stbuf;
12113640Ssam
12217832Sralph /*
12313640Ssam * cntrl - this routine will execute the conversation
12413640Ssam * between the two machines after both programs are
12513640Ssam * running.
12613640Ssam *
12713640Ssam * return codes
12813640Ssam * SUCCESS - ok
12913640Ssam * FAIL - failed
13013640Ssam */
13113640Ssam
cntrl(role,wkpre)13213640Ssam cntrl(role, wkpre)
13313640Ssam int role;
13413640Ssam char *wkpre;
13513640Ssam {
13613640Ssam char msg[BUFSIZ], rqstr[BUFSIZ];
13713640Ssam register FILE *fp;
13813640Ssam int filemode;
13913640Ssam char filename[MAXFULLNAME], wrktype, *wrkvec[20];
14013640Ssam extern (*Rdmsg)(), (*Wrmsg)();
14113640Ssam extern char *index(), *lastpart();
14213640Ssam int status = 1;
14313640Ssam register int i, narg;
14413640Ssam int mailopt, ntfyopt;
14513640Ssam int ret;
14613640Ssam static int pnum, tmpnum = 0;
14717832Sralph extern int ReverseRole;
14813640Ssam
14913640Ssam pnum = getpid();
15013640Ssam Wfile[0] = '\0';
15118617Sralph willturn = turntime > 0;
15218617Sralph remaster:
15318617Sralph #ifdef USG
15418617Sralph time(&LastTurned.time);
15518617Sralph LastTurned.millitm = 0;
15618617Sralph #else !USG
15718617Sralph ftime(&LastTurned);
15818617Sralph #endif !USG
15918617Sralph send_or_receive = RESET;
16023591Sbloom HaveSentHup = 0;
16113640Ssam top:
16213640Ssam for (i = 0; i < sizeof wrkvec / sizeof wrkvec[0]; i++)
16313640Ssam wrkvec[i] = 0;
16417832Sralph DEBUG(4, "*** TOP *** - role=%s\n", role ? "MASTER" : "SLAVE");
16534165Srick setproctitle("%s: %s", Rmtname, role ? "MASTER" : "SLAVE");
16623591Sbloom setupline(RESET);
16725125Sbloom if (Now.time > (LastCheckedNoLogin.time+60)) {
16825125Sbloom LastCheckedNoLogin = Now;
16925125Sbloom if (access(NOLOGIN, 0) == 0) {
17025125Sbloom logent(NOLOGIN, "UUCICO SHUTDOWN");
17125125Sbloom if (Debug > 4)
17225125Sbloom logent("DEBUGGING", "continuing anyway");
17325125Sbloom else {
17425125Sbloom WMESG(HUP, YES);
17525125Sbloom RMESG(HUP, msg, 1);
17625125Sbloom goto process;
17725125Sbloom }
17818617Sralph }
17918617Sralph }
18013640Ssam if (role == MASTER) {
18113640Ssam /* get work */
18217832Sralph if (ReverseRole || (narg = gtwvec(Wfile, Spool, wkpre, wrkvec)) == 0) {
18317832Sralph ReverseRole = 0;
18413640Ssam WMESG(HUP, "");
18513640Ssam RMESG(HUP, msg, 1);
18613640Ssam goto process;
18713640Ssam }
18813640Ssam wrktype = W_TYPE[0];
18913640Ssam
19013640Ssam msg[0] = '\0';
19113640Ssam for (i = 1; i < narg; i++) {
19213640Ssam strcat(msg, " ");
19313640Ssam strcat(msg, wrkvec[i]);
19413640Ssam }
19513640Ssam
19613640Ssam if (wrktype == XUUCP) {
19713640Ssam sprintf(rqstr, "X %s", msg);
19813640Ssam logent(rqstr, "REQUEST");
19913640Ssam goto sendmsg;
20013640Ssam }
20117832Sralph mailopt = index(W_OPTNS, 'm') != NULL;
20217832Sralph ntfyopt = index(W_OPTNS, 'n') != NULL;
20313640Ssam
20433560Srick if (narg < 5 || W_TYPE[1] != '\0') {
20517832Sralph char *bnp;
20617832Sralph bnp = rindex(Wfile, '/');
20717832Sralph sprintf(rqstr, "%s/%s", CORRUPT, bnp ? bnp + 1 : Wfile);
20817832Sralph xmv(Wfile, rqstr);
20933946Srick syslog(LOG_WARNING, "%s CORRUPTED: %d args", Wfile,
21033946Srick narg);
21117832Sralph Wfile[0] = '\0';
21217832Sralph goto top;
21317832Sralph }
21413640Ssam sprintf(User, "%.9s", W_USER);
21534165Srick sprintf(rqstr, "(%s %s %s %s)", W_TYPE, W_FILE1,
21613640Ssam W_FILE2, W_USER);
21713640Ssam logent(rqstr, "REQUEST");
21813640Ssam if (wrktype == SNDFILE ) {
21913640Ssam strcpy(filename, W_FILE1);
22013640Ssam i = expfile(filename);
22117832Sralph DEBUG(4, "expfile type - %d, ", i);
22213640Ssam if (i != 0 && chkpth(User, "", filename))
22313640Ssam goto e_access;
22413640Ssam strcpy(Dfile, W_DFILE);
22513640Ssam fp = NULL;
22613640Ssam if (index(W_OPTNS, 'c') == NULL) {
22713640Ssam fp = fopen(subfile(Dfile), "r");
22813640Ssam if (fp != NULL)
22913640Ssam i = 0;
23013640Ssam }
23113640Ssam if (fp == NULL &&
23213640Ssam (fp = fopen(subfile(filename), "r")) == NULL) {
23313640Ssam /* can not read data file */
23417832Sralph logent("CAN'T READ DATA", _FAILED);
23523591Sbloom TransferSucceeded = 1; /* else will keep sending */
23617832Sralph USRF(USR_LOCACC);
23713640Ssam unlinkdf(Dfile);
23813640Ssam lnotify(User, filename, "can't access");
23913640Ssam goto top;
24013640Ssam }
24113640Ssam /* if file exists but is not generally readable... */
24213640Ssam if (i != 0 && fstat(fileno(fp), &stbuf) == 0
24313640Ssam && (stbuf.st_mode & ANYREAD) == 0) {
24413640Ssam e_access:;
24513640Ssam /* access denied */
24633946Srick if (fp != NULL) {
24733946Srick fclose(fp);
24833946Srick fp = NULL;
24933946Srick }
25023591Sbloom TransferSucceeded = 1; /* else will keep sending */
25113640Ssam logent("DENIED", "ACCESS");
25217832Sralph USRF(USR_LOCACC);
25313640Ssam unlinkdf(W_DFILE);
25413640Ssam lnotify(User, filename, "access denied");
25513640Ssam goto top;
25613640Ssam }
25713640Ssam
25823591Sbloom setupline(SNDFILE);
25913640Ssam }
26013640Ssam
26113640Ssam if (wrktype == RCVFILE) {
26213640Ssam strcpy(filename, W_FILE2);
26313640Ssam expfile(filename);
26413640Ssam if (chkpth(User, "", filename)
26513640Ssam || chkperm(filename, index(W_OPTNS, 'd'))) {
26613640Ssam /* access denied */
26713640Ssam logent("DENIED", "ACCESS");
26823591Sbloom TransferSucceeded = 1; /* else will keep trying */
26917832Sralph USRF(USR_LOCACC);
27013640Ssam lnotify(User, filename, "access denied");
27113640Ssam goto top;
27213640Ssam }
27313640Ssam sprintf(Dfile, "%s/TM.%05d.%03d", Spool, pnum, tmpnum++);
27413640Ssam if ((fp = fopen(subfile(Dfile), "w")) == NULL) {
27513640Ssam /* can not create temp */
27617832Sralph logent("CAN'T CREATE TM", _FAILED);
27717832Sralph USRF(USR_LNOTMP);
27813640Ssam unlinkdf(Dfile);
27913640Ssam goto top;
28013640Ssam }
28123591Sbloom setupline(RCVFILE);
28213640Ssam }
28313640Ssam sendmsg:
28417832Sralph DEBUG(4, "wrktype - %c\n", wrktype);
28513640Ssam WMESG(wrktype, msg);
28613640Ssam RMESG(wrktype, msg, 1);
28713640Ssam goto process;
28813640Ssam }
28913640Ssam
29013640Ssam /* role is slave */
29113640Ssam RAMESG(msg, 1);
29218617Sralph if (willturn < 0)
29318617Sralph willturn = msg[0] == HUP;
29418617Sralph
29513640Ssam process:
29617832Sralph DEBUG(4, "PROCESS: msg - %s\n", msg);
29713640Ssam switch (msg[0]) {
29813640Ssam
29913640Ssam case RQSTCMPT:
30017832Sralph DEBUG(4, "RQSTCMPT:\n", CNULL);
30113640Ssam if (msg[1] == 'N') {
30213640Ssam i = atoi(&msg[2]);
30323591Sbloom if (i<0 || i>EM_MAX)
30423591Sbloom i = 0;
30517832Sralph USRF( 1 << i );
30617832Sralph logent(Em_msg[i], "REQUEST FAILED");
30725125Sbloom TransferSucceeded = 1; /* He had his chance */
30813640Ssam }
30923591Sbloom if (msg[1] == 'Y') {
31017832Sralph USRF(USR_COK);
31123591Sbloom TransferSucceeded = 1;
31223591Sbloom }
31333946Srick if (role == MASTER)
31433591Srick notify(mailopt, W_USER, W_FILE1, Rmtname, &msg[1]);
31533946Srick
31633946Srick if (msg[2] == 'M' && role == MASTER) {
31718617Sralph extern int Nfiles;
31818617Sralph WMESG(HUP, "");
31918617Sralph RMESG(HUP, msg, 1);
32018617Sralph logent(Rmtname, "TURNAROUND");
32118617Sralph #ifdef USG
32218617Sralph time(&LastTurned.time);
32318617Sralph LastTurned.millitm = 0;
32418617Sralph #else !USG
32518617Sralph ftime(&LastTurned);
32618617Sralph #endif !USG
32718617Sralph Nfiles = 0; /* force rescan of queue for work */
32818617Sralph goto process;
32918617Sralph }
33013640Ssam goto top;
33113640Ssam
33213640Ssam case HUP:
33317832Sralph DEBUG(4, "HUP:\n", CNULL);
33423591Sbloom HaveSentHup = 1;
33513640Ssam if (msg[1] == 'Y') {
33617832Sralph if (role == MASTER)
33717832Sralph WMESG(HUP, YES);
33813640Ssam (*Turnoff)();
33913640Ssam Rdmsg = Imsg;
34013640Ssam Wrmsg = Omsg;
34117832Sralph return SUCCESS;
34213640Ssam }
34313640Ssam
34413640Ssam if (msg[1] == 'N') {
34533946Srick if (role != MASTER) {
34633946Srick syslog(LOG_ERR, "Wrong Role - HUP");
34733946Srick cleanup(FAIL);
34833946Srick }
34913640Ssam role = SLAVE;
35018617Sralph goto remaster;
35113640Ssam }
35213640Ssam
35313640Ssam /* get work */
35413640Ssam if (!iswrk(Wfile, "chk", Spool, wkpre)) {
35513640Ssam WMESG(HUP, YES);
35613640Ssam RMESG(HUP, msg, 1);
35713640Ssam goto process;
35813640Ssam }
35913640Ssam
36013640Ssam WMESG(HUP, NO);
36133946Srick /*
36233946Srick * want to create an orphan uuxqt,
36333946Srick * so a double-fork is needed.
36433946Srick */
36533946Srick if (fork() == 0) {
36633946Srick xuuxqt();
36733946Srick _exit(0);
36833946Srick }
36933946Srick wait((int *)0);
37013640Ssam role = MASTER;
37118617Sralph goto remaster;
37213640Ssam
37313640Ssam case XUUCP:
37413640Ssam if (role == MASTER) {
37513640Ssam goto top;
37613640Ssam }
37713640Ssam
37813640Ssam /* slave part */
37917832Sralph i = getargs(msg, wrkvec, 20);
38013640Ssam strcpy(filename, W_FILE1);
38117832Sralph if (index(filename, ';') != NULL || index(W_FILE2, ';') != NULL
38217832Sralph || i < 3) {
38313640Ssam WMESG(XUUCP, NO);
38413640Ssam goto top;
38513640Ssam }
38613640Ssam expfile(filename);
38713640Ssam if (chkpth("", Rmtname, filename)) {
38813640Ssam WMESG(XUUCP, NO);
38913640Ssam logent("XUUCP DENIED", filename);
39017832Sralph USRF(USR_XUUCP);
39113640Ssam goto top;
39213640Ssam }
39313640Ssam sprintf(rqstr, "%s %s", filename, W_FILE2);
39413640Ssam xuucp(rqstr);
39513640Ssam WMESG(XUUCP, YES);
39613640Ssam goto top;
39713640Ssam
39813640Ssam case SNDFILE:
39913640Ssam /* MASTER section of SNDFILE */
40013640Ssam
40113640Ssam DEBUG(4, "%s\n", "SNDFILE:");
40213640Ssam if (msg[1] == 'N') {
40313640Ssam i = atoi(&msg[2]);
40413640Ssam if (i < 0 || i > EM_MAX)
40513640Ssam i = 0;
40617832Sralph logent(Em_msg[i], "REQUEST FAILED");
40717832Sralph USRF( 1 << i );
40813640Ssam fclose(fp);
40913640Ssam fp = NULL;
41025125Sbloom /* dont send him files he can't save */
41117832Sralph if (strcmp(&msg[1], EM_NOTMP) == 0) {
41217832Sralph WMESG(HUP, "");
41317832Sralph RMESG(HUP, msg, 1);
41417832Sralph goto process;
41517832Sralph }
41633591Srick notify(mailopt, W_USER, W_FILE1, Rmtname, &msg[1]);
41733946Srick if (role != MASTER) {
41833946Srick syslog(LOG_ERR, "Wrong Role - SN");
41933946Srick cleanup(FAIL);
42033946Srick }
42133560Srick unlinkdf(W_DFILE);
42213640Ssam goto top;
42313640Ssam }
42413640Ssam
42513640Ssam if (msg[1] == 'Y') {
42613640Ssam /* send file */
42733946Srick if (role != MASTER) {
42833946Srick syslog(LOG_ERR, "Wrong Role - SY");
42933946Srick cleanup(FAIL);
43033946Srick }
43133946Srick if (fstat(fileno(fp), &stbuf) < 0) {
43233946Srick syslog(LOG_ERR, "stat(%s) failed: %m",filename);
43333946Srick cleanup(FAIL);
43433946Srick }
43513640Ssam i = 1 + (int)(stbuf.st_size / XFRRATE);
43617832Sralph if (send_or_receive != SNDFILE) {
43717832Sralph send_or_receive = SNDFILE;
43817832Sralph systat(Rmtname, SS_INPROGRESS, "SENDING");
43917832Sralph }
44013640Ssam ret = (*Wrdata)(fp, Ofn);
44113640Ssam fclose(fp);
44213640Ssam fp = NULL;
44317832Sralph if (ret != SUCCESS) {
44413640Ssam (*Turnoff)();
44517832Sralph USRF(USR_CFAIL);
44617832Sralph return FAIL;
44713640Ssam }
44813640Ssam RMESG(RQSTCMPT, msg, i);
44913640Ssam unlinkdf(W_DFILE);
45013640Ssam goto process;
45113640Ssam }
45213640Ssam
45313640Ssam /* SLAVE section of SNDFILE */
45433946Srick if (role != SLAVE) {
45533946Srick syslog(LOG_ERR, "Wrong Role - SLAVE");
45633946Srick cleanup(FAIL);
45733946Srick }
45813640Ssam
45913640Ssam /* request to receive file */
46013640Ssam /* check permissions */
46117832Sralph i = getargs(msg, wrkvec, 20);
46217832Sralph if (i < 5) {
46317832Sralph char *bnp;
46417832Sralph bnp = rindex(Wfile, '/');
46517832Sralph sprintf(rqstr, "%s/%s", CORRUPT, bnp ? bnp + 1 : Wfile);
46617832Sralph xmv(Wfile, rqstr);
46733946Srick syslog(LOG_WARNING, "%s CORRUPTED: %d args", Wfile, i);
46817832Sralph Wfile[0] = '\0';
46917832Sralph goto top;
47017832Sralph }
47134165Srick sprintf(rqstr, "(%s %s %s %s)", W_TYPE, W_FILE1, W_FILE2,
47234165Srick W_USER);
47313640Ssam logent(rqstr, "REQUESTED");
47413640Ssam DEBUG(4, "msg - %s\n", msg);
47513640Ssam strcpy(filename, W_FILE2);
47613640Ssam /* Run uuxqt occasionally */
47713640Ssam if (filename[0] == XQTPRE) {
47813640Ssam if (++nXfiles > 10) {
47913640Ssam nXfiles = 0;
48017832Sralph /*
48117832Sralph * want to create an orphan uuxqt,
48217832Sralph * so a double-fork is needed.
48313640Ssam */
48417832Sralph if (fork() == 0) {
48517832Sralph xuuxqt();
48617832Sralph _exit(0);
48717832Sralph }
48817832Sralph wait((int *)0);
48913640Ssam }
49013640Ssam }
49117832Sralph /* expand filename, i is set to 0 if this is
49213640Ssam * is a vanilla spool file, so no stat(II)s are needed */
49313640Ssam i = expfile(filename);
49413640Ssam DEBUG(4, "expfile type - %d\n", i);
49513640Ssam if (i != 0) {
49613640Ssam if (chkpth("", Rmtname, filename)
49713640Ssam || chkperm(filename, index(W_OPTNS, 'd'))) {
49813640Ssam WMESG(SNDFILE, EM_RMTACC);
49913640Ssam logent("DENIED", "PERMISSION");
50013640Ssam goto top;
50113640Ssam }
50213640Ssam if (isdir(filename)) {
50313640Ssam strcat(filename, "/");
50413640Ssam strcat(filename, lastpart(W_FILE1));
50513640Ssam }
50613640Ssam }
50713640Ssam sprintf(User, "%.9s", W_USER);
50813640Ssam
50913640Ssam DEBUG(4, "chkpth ok Rmtname - %s\n", Rmtname);
51017832Sralph /* speed things up by OKing file before
51117832Sralph * creating TM file. If the TM file cannot be created,
51217832Sralph * then the conversation bombs, but that seems reasonable,
51317832Sralph * as there are probably serious problems then.
51417832Sralph */
51517832Sralph WMESG(SNDFILE, YES);
51613640Ssam sprintf(Dfile, "%s/TM.%05d.%03d", Spool, pnum, tmpnum++);
51713640Ssam if((fp = fopen(subfile(Dfile), "w")) == NULL) {
51817832Sralph /* WMESG(SNDFILE, EM_NOTMP);*/
51917832Sralph logent("CAN'T OPEN", "TM FILE");
52013640Ssam unlinkdf(Dfile);
52117832Sralph (*Turnoff)();
52217832Sralph return FAIL;
52313640Ssam }
52413640Ssam
52517832Sralph if (send_or_receive != RCVFILE) {
52617832Sralph send_or_receive = RCVFILE;
52717832Sralph systat(Rmtname, SS_INPROGRESS, "RECEIVING");
52817832Sralph }
52913640Ssam ret = (*Rddata)(Ifn, fp);
53013640Ssam fflush(fp);
53113640Ssam if (ferror(fp) || fclose(fp))
53213640Ssam ret = FAIL;
53323591Sbloom
53417832Sralph if (ret != SUCCESS) {
53517832Sralph (void) unlinkdf(Dfile);
53613640Ssam (*Turnoff)();
53717832Sralph return FAIL;
53813640Ssam }
53913640Ssam /* copy to user directory */
54013640Ssam ntfyopt = index(W_OPTNS, 'n') != NULL;
54113640Ssam status = xmv(Dfile, filename);
54218617Sralph
54318617Sralph if (willturn && Now.time > (LastTurned.time+turntime)
54418617Sralph && iswrk(Wfile, "chk", Spool, wkpre)) {
54518617Sralph WMESG(RQSTCMPT, status ? EM_RMTCP : "YM");
54618617Sralph willturn = -1;
54718617Sralph } else
54818617Sralph WMESG(RQSTCMPT, status ? EM_RMTCP : YES);
54917832Sralph if (i == 0)
55017832Sralph ; /* vanilla file, nothing to do */
55117832Sralph else if (status == 0) {
55217832Sralph if (W_MODE == 0 || sscanf(W_MODE, "%o", &filemode) != 1)
55313640Ssam filemode = BASEMODE;
55417832Sralph chmod(subfile(filename), (filemode|BASEMODE)&0777);
55513640Ssam arrived(ntfyopt, filename, W_NUSER, Rmtname, User);
55617832Sralph } else {
55717832Sralph logent(_FAILED, "COPY");
55813640Ssam status = putinpub(filename, Dfile, W_USER);
55913640Ssam DEBUG(4, "->PUBDIR %d\n", status);
56013640Ssam if (status == 0)
56117832Sralph arrived(ntfyopt, filename, W_NUSER, Rmtname, User);
56213640Ssam }
56313640Ssam
56413640Ssam goto top;
56513640Ssam
56613640Ssam case RCVFILE:
56713640Ssam /* MASTER section of RCVFILE */
56813640Ssam
56913640Ssam DEBUG(4, "%s\n", "RCVFILE:");
57013640Ssam if (msg[1] == 'N') {
57113640Ssam i = atoi(&msg[2]);
57213640Ssam if (i < 0 || i > EM_MAX)
57313640Ssam i = 0;
57417832Sralph logent(Em_msg[i], "REQUEST FAILED");
57517832Sralph USRF( 1 << i );
57617832Sralph fclose(fp);
57717832Sralph fp = NULL;
57833591Srick notify(mailopt, W_USER, W_FILE1, Rmtname, &msg[1]);
57933946Srick if (role != MASTER) {
58033946Srick syslog(LOG_ERR, "Wrong Role - RN");
58133946Srick cleanup(FAIL);
58233946Srick }
58313640Ssam unlinkdf(Dfile);
58413640Ssam goto top;
58513640Ssam }
58613640Ssam
58713640Ssam if (msg[1] == 'Y') {
58813640Ssam /* receive file */
58933946Srick if (role != MASTER) {
59033946Srick syslog(LOG_ERR, "Wrong Role - RY");
59133946Srick cleanup(FAIL);
59233946Srick }
59317832Sralph if (send_or_receive != RCVFILE) {
59417832Sralph send_or_receive = RCVFILE;
59517832Sralph systat(Rmtname, SS_INPROGRESS, "RECEIVING");
59617832Sralph }
59713640Ssam ret = (*Rddata)(Ifn, fp);
59813640Ssam fflush(fp);
59913640Ssam if (ferror(fp) || fclose(fp))
60013640Ssam ret = FAIL;
60117832Sralph if (ret != SUCCESS) {
60217832Sralph unlinkdf(Dfile);
60313640Ssam (*Turnoff)();
60417832Sralph USRF(USR_CFAIL);
60517832Sralph return FAIL;
60613640Ssam }
60713640Ssam /* copy to user directory */
60813640Ssam if (isdir(filename)) {
60913640Ssam strcat(filename, "/");
61013640Ssam strcat(filename, lastpart(W_FILE1));
61113640Ssam }
61213640Ssam status = xmv(Dfile, filename);
61333946Srick WMESG(RQSTCMPT, status ? EM_RMTCP : YES);
61413640Ssam notify(mailopt, W_USER, filename, Rmtname,
61525964Sbloom status ? EM_LOCCP : YES);
61613640Ssam if (status == 0) {
61713640Ssam sscanf(&msg[2], "%o", &filemode);
61813640Ssam if (filemode <= 0)
61913640Ssam filemode = BASEMODE;
62017832Sralph chmod(subfile(filename), (filemode|BASEMODE)&0777);
62117832Sralph USRF(USR_COK);
62225964Sbloom } else {
62317832Sralph logent(_FAILED, "COPY");
62413640Ssam putinpub(filename, Dfile, W_USER);
62517832Sralph USRF(USR_LOCCP);
62613640Ssam }
62733946Srick if (msg[strlen(msg)-1] == 'M') {
62833946Srick extern int Nfiles;
62933946Srick WMESG(HUP, "");
63033946Srick RMESG(HUP, msg, 1);
63133946Srick logent(Rmtname, "TURNAROUND");
63233946Srick #ifdef USG
63333946Srick time(&LastTurned.time);
63433946Srick LastTurned.millitm = 0;
63533946Srick #else !USG
63633946Srick ftime(&LastTurned);
63733946Srick #endif !USG
63833946Srick Nfiles = 0; /* force rescan of queue for work */
63933946Srick goto process;
64033946Srick }
64113640Ssam goto top;
64213640Ssam }
64313640Ssam
64413640Ssam /* SLAVE section of RCVFILE */
64533946Srick if (role != SLAVE) {
64633946Srick syslog(LOG_ERR, "Wrong Role - SLAVE RCV");
64733946Srick cleanup(FAIL);
64833946Srick }
64913640Ssam
65013640Ssam /* request to send file */
65134165Srick sprintf(rqstr,"(%s)", msg);
65213640Ssam logent(rqstr, "REQUESTED");
65313640Ssam
65413640Ssam /* check permissions */
65517832Sralph i = getargs(msg, wrkvec, 20);
65617832Sralph if (i < 4) {
65717832Sralph char *bnp;
65817832Sralph bnp = rindex(Wfile, '/');
65917832Sralph sprintf(rqstr, "%s/%s", CORRUPT, bnp ? bnp + 1 : Wfile);
66017832Sralph xmv(Wfile, rqstr);
66133946Srick syslog(LOG_WARNING, "%s CORRUPTED: %d args", Wfile, i);
66217832Sralph Wfile[0] = '\0';
66317832Sralph goto top;
66417832Sralph }
66513640Ssam DEBUG(4, "msg - %s\n", msg);
66613640Ssam DEBUG(4, "W_FILE1 - %s\n", W_FILE1);
66713640Ssam strcpy(filename, W_FILE1);
66813640Ssam expfile(filename);
66913640Ssam if (isdir(filename)) {
67013640Ssam strcat(filename, "/");
67113640Ssam strcat(filename, lastpart(W_FILE2));
67213640Ssam }
67313640Ssam sprintf(User, "%.9s", W_USER);
67413640Ssam if (chkpth("", Rmtname, filename) || anyread(filename)) {
67513640Ssam WMESG(RCVFILE, EM_RMTACC);
67613640Ssam logent("DENIED", "PERMISSION");
67713640Ssam goto top;
67813640Ssam }
67913640Ssam DEBUG(4, "chkpth ok Rmtname - %s\n", Rmtname);
68013640Ssam
68113640Ssam if ((fp = fopen(subfile(filename), "r")) == NULL) {
68213640Ssam WMESG(RCVFILE, EM_RMTACC);
68313640Ssam logent("CAN'T OPEN", "DENIED");
68413640Ssam goto top;
68513640Ssam }
68613640Ssam
68713640Ssam /* ok to send file */
68833946Srick if (fstat(fileno(fp), &stbuf) < 0) {
68933946Srick syslog(LOG_ERR, "stat(%s) failed: %m", filename);
69033946Srick cleanup(FAIL);
69133946Srick }
69233946Srick
69313640Ssam i = 1 + (int)(stbuf.st_size / XFRRATE);
69433946Srick if (willturn && Now.time > (LastTurned.time+turntime)
69533946Srick && iswrk(Wfile, "chk", Spool, wkpre)) {
69633946Srick willturn = -1;
69733946Srick }
69833946Srick sprintf(msg, "%s %o%s", YES, (int)stbuf.st_mode & 0777,
69933946Srick willturn < 0 ? " M" : "");
70013640Ssam WMESG(RCVFILE, msg);
70117832Sralph if (send_or_receive != SNDFILE) {
70217832Sralph send_or_receive = SNDFILE;
70317832Sralph systat(Rmtname, SS_INPROGRESS, "SENDING");
70417832Sralph }
70513640Ssam ret = (*Wrdata)(fp, Ofn);
70613640Ssam fclose(fp);
70717832Sralph if (ret != SUCCESS) {
70813640Ssam (*Turnoff)();
70917832Sralph return FAIL;
71013640Ssam }
71113640Ssam RMESG(RQSTCMPT, msg, i);
71213640Ssam goto process;
71313640Ssam }
71413640Ssam (*Turnoff)();
71517832Sralph return FAIL;
71613640Ssam }
71713640Ssam
71813640Ssam
71925964Sbloom /*
72025964Sbloom * read message 'c'. try 'n' times
72113640Ssam *
72225964Sbloom * return code: SUCCESS | FAIL
72313640Ssam */
rmesg(c,msg,n)72413640Ssam rmesg(c, msg, n)
72513640Ssam register char *msg, c;
72613640Ssam register int n;
72713640Ssam {
72825964Sbloom char str[MAXFULLNAME];
72913640Ssam
73013640Ssam DEBUG(4, "rmesg - '%c' ", c);
73117832Sralph while ((*Rdmsg)(msg, Ifn) != SUCCESS) {
73217832Sralph if (--n > 0) {
73317832Sralph sprintf(str, "%d", n);
73417832Sralph logent(str, "PATIENCE");
73513640Ssam continue;
73617832Sralph }
73717832Sralph DEBUG(4, "got FAIL\n", CNULL);
73817832Sralph if (c != '\0')
73917832Sralph sprintf(str, "expected '%c' got FAIL (%d)", c, errno);
74017832Sralph else
74117832Sralph sprintf(str, "expected ANY got FAIL (%d)", errno);
74213640Ssam logent(str, "BAD READ");
74317832Sralph return FAIL;
74413640Ssam }
74513640Ssam if (c != '\0' && msg[0] != c) {
74613640Ssam DEBUG(4, "got %s\n", msg);
74717832Sralph sprintf(str, "expected '%c' got %s", c, msg);
74813640Ssam logent(str, "BAD READ");
74917832Sralph return FAIL;
75013640Ssam }
75117832Sralph DEBUG(4, "got %s\n", msg);
75217832Sralph return SUCCESS;
75313640Ssam }
75413640Ssam
75513640Ssam
75625964Sbloom /*
75725964Sbloom * write a message (type m)
75813640Ssam *
75925964Sbloom * return codes: SUCCESS - ok | FAIL - ng
76013640Ssam */
wmesg(m,s)76113640Ssam wmesg(m, s)
76213640Ssam register char *s, m;
76313640Ssam {
76417832Sralph DEBUG(4, "wmesg '%c' ", m);
76517832Sralph DEBUG(4, "%s\n", s);
76617832Sralph return (*Wrmsg)(m, s, Ofn);
76713640Ssam }
76813640Ssam
76925964Sbloom /*
77025964Sbloom * mail results of command
77113640Ssam *
77213640Ssam * return codes: none
77313640Ssam */
notify(mailopt,user,file,sys,msgcode)77413640Ssam notify(mailopt, user, file, sys, msgcode)
77513640Ssam char *user, *file, *sys, *msgcode;
77613640Ssam {
77725964Sbloom char str[BUFSIZ];
77813640Ssam int i;
77913640Ssam char *msg;
78013640Ssam
78113640Ssam if (!mailopt && *msgcode == 'Y')
78213640Ssam return;
78313640Ssam if (*msgcode == 'Y')
78413640Ssam msg = "copy succeeded";
78513640Ssam else {
78613640Ssam i = atoi(msgcode + 1);
78713640Ssam if (i < 1 || i > EM_MAX)
78813640Ssam i = 0;
78913640Ssam msg = Em_msg[i];
79013640Ssam }
79117832Sralph sprintf(str, "file %s!%s -- %s\n",
79217832Sralph sys,file, msg);
79317832Sralph mailst(user, str, CNULL);
79413640Ssam return;
79513640Ssam }
79613640Ssam
79725964Sbloom /*
79825964Sbloom * local notify
79913640Ssam *
80013640Ssam * return code - none
80113640Ssam */
lnotify(user,file,mesg)80213640Ssam lnotify(user, file, mesg)
80313640Ssam char *user, *file, *mesg;
80413640Ssam {
80513640Ssam char mbuf[200];
80617832Sralph sprintf(mbuf, "file %s!%s -- %s\n", Myname, file, mesg);
80717832Sralph mailst(user, mbuf, CNULL);
80813640Ssam return;
80913640Ssam }
81013640Ssam
81133591Srick char UsingProtocol;
81233591Srick
81325964Sbloom /*
81425964Sbloom * converse with the remote machine, agree upon a protocol (if possible)
81525964Sbloom * and start the protocol.
81613640Ssam *
81713640Ssam * return codes:
81813640Ssam * SUCCESS - successful protocol selection
81913640Ssam * FAIL - can't find common or open failed
82013640Ssam */
startup(role)82113640Ssam startup(role)
82213640Ssam int role;
82313640Ssam {
82413640Ssam extern (*Rdmsg)(), (*Wrmsg)();
82513640Ssam extern char *blptcl(), fptcl();
82617832Sralph char msg[BUFSIZ], str[MAXFULLNAME];
82713640Ssam
82813640Ssam Rdmsg = Imsg;
82913640Ssam Wrmsg = Omsg;
83013640Ssam if (role == MASTER) {
83113640Ssam RMESG(SLTPTCL, msg, 1);
83213640Ssam if ((str[0] = fptcl(&msg[1])) == NULL) {
83313640Ssam /* no protocol match */
83413640Ssam WMESG(USEPTCL, NO);
83517832Sralph return FAIL;
83613640Ssam }
83713640Ssam str[1] = '\0';
83813640Ssam WMESG(USEPTCL, str);
83913640Ssam if (stptcl(str) != 0)
84017832Sralph return FAIL;
84113640Ssam DEBUG(4, "protocol %s\n", str);
84233591Srick UsingProtocol = str[0];
84317832Sralph return SUCCESS;
84413640Ssam }
84513640Ssam else {
84613640Ssam WMESG(SLTPTCL, blptcl(str));
84713640Ssam RMESG(USEPTCL, msg, 1);
84813640Ssam if (msg[1] == 'N') {
84917832Sralph return FAIL;
85013640Ssam }
85113640Ssam
85213640Ssam if (stptcl(&msg[1]) != 0)
85317832Sralph return FAIL;
85413640Ssam DEBUG(4, "Protocol %s\n", msg);
85533591Srick UsingProtocol = msg[1];
85617832Sralph return SUCCESS;
85713640Ssam }
85813640Ssam }
85913640Ssam
86025964Sbloom /*
86125964Sbloom * choose a protocol from the input string (str) and return the it
86213640Ssam *
86313640Ssam * return codes:
86413640Ssam * '\0' - no acceptable protocol
86513640Ssam * any character - the chosen protocol
86613640Ssam */
86713640Ssam char
fptcl(str)86813640Ssam fptcl(str)
86913640Ssam register char *str;
87013640Ssam {
87113640Ssam register struct Proto *p;
87225964Sbloom extern char LineType[];
87313640Ssam
87413640Ssam for (p = Ptbl; p->P_id != '\0'; p++) {
87523591Sbloom #ifdef TCPIP
87623591Sbloom /* Only use 't' on TCP/IP */
87725964Sbloom if (p->P_id == 't' && strcmp("TCP", LineType))
87817662Sralph continue;
87923591Sbloom #endif TCPIP
88023591Sbloom #ifdef PAD
88117832Sralph /* only use 'f' protocol on PAD */
88225964Sbloom if (p->P_id == 'f' && strcmp("PAD", LineType))
88317832Sralph continue;
88423591Sbloom #endif PAD
88513640Ssam if (index(str, p->P_id) != NULL) {
88617832Sralph return p->P_id;
88713640Ssam }
88813640Ssam }
88913640Ssam
89017832Sralph return '\0';
89113640Ssam }
89213640Ssam
89325964Sbloom /*
89425964Sbloom * build a string of the letters of the available protocols
89513640Ssam */
89613640Ssam char *
blptcl(str)89713640Ssam blptcl(str)
89813640Ssam register char *str;
89913640Ssam {
90013640Ssam register struct Proto *p;
90113640Ssam register char *s;
90213640Ssam
90317832Sralph for (p = Ptbl, s = str; (*s++ = p->P_id) != '\0'; p++)
90417832Sralph ;
90517662Sralph *s = '\0';
90617832Sralph return str;
90713640Ssam }
90813640Ssam
90925964Sbloom /*
91025964Sbloom * this routine will set up the six routines
91113640Ssam * (Rdmsg, Wrmsg, Rddata, Wrdata, Turnon, Turnoff) for the
91213640Ssam * desired protocol.
91313640Ssam *
91413640Ssam * return codes:
91513640Ssam * SUCCESS - ok
91613640Ssam * FAIL - no find or failed to open
91713640Ssam *
91813640Ssam */
stptcl(c)91913640Ssam stptcl(c)
92013640Ssam register char *c;
92113640Ssam {
92213640Ssam register struct Proto *p;
92313640Ssam
92413640Ssam for (p = Ptbl; p->P_id != '\0'; p++) {
92513640Ssam if (*c == p->P_id) {
92613640Ssam /* found protocol - set routines */
92713640Ssam Rdmsg = p->P_rdmsg;
92813640Ssam Wrmsg = p->P_wrmsg;
92913640Ssam Rddata = p->P_rddata;
93013640Ssam Wrdata = p->P_wrdata;
93113640Ssam Turnon = p->P_turnon;
93213640Ssam Turnoff = p->P_turnoff;
93317832Sralph if ((*Turnon)() != SUCCESS)
93417832Sralph return FAIL;
93513640Ssam DEBUG(4, "Proto started %c\n", *c);
93617832Sralph return SUCCESS;
93713640Ssam }
93813640Ssam }
93913640Ssam DEBUG(4, "Proto start-fail %c\n", *c);
94017832Sralph return FAIL;
94113640Ssam }
94213640Ssam
94325964Sbloom /*
94425964Sbloom * put file in public place. if successful, filename is modified
94513640Ssam *
94625964Sbloom * return code SUCCESS | FAIL
94713640Ssam */
94813640Ssam
putinpub(file,tmp,user)94913640Ssam putinpub(file, tmp, user)
95025964Sbloom register char *file, *tmp, *user;
95113640Ssam {
95213640Ssam char fullname[MAXFULLNAME];
95313640Ssam char *lastpart();
95413640Ssam int status;
95513640Ssam
95613640Ssam sprintf(fullname, "%s/%s/", PUBDIR, user);
95713640Ssam if (mkdirs(fullname) != 0) {
95813640Ssam /* can not make directories */
95925964Sbloom DEBUG(1, "Cannot mkdirs(%s)\n", fullname);
96017832Sralph return FAIL;
96113640Ssam }
96213640Ssam strcat(fullname, lastpart(file));
96313640Ssam status = xmv(tmp, fullname);
96413640Ssam if (status == 0) {
96513640Ssam strcpy(file, fullname);
96613640Ssam chmod(subfile(fullname), BASEMODE);
96713640Ssam }
96817832Sralph return status;
96913640Ssam }
97013640Ssam
97125964Sbloom /*
97225964Sbloom * unlink D. file
97313640Ssam *
97413640Ssam * return code - none
97513640Ssam */
97613640Ssam
unlinkdf(file)97713640Ssam unlinkdf(file)
97813640Ssam register char *file;
97913640Ssam {
98013640Ssam if (strlen(file) > 6)
98113640Ssam unlink(subfile(file));
98213640Ssam return;
98313640Ssam }
98413640Ssam
98525964Sbloom /*
98625964Sbloom * notify receiver of arrived file
98713640Ssam *
98813640Ssam * return code - none
98913640Ssam */
arrived(opt,file,nuser,rmtsys,rmtuser)99013640Ssam arrived(opt, file, nuser, rmtsys, rmtuser)
99113640Ssam char *file, *nuser, *rmtsys, *rmtuser;
99213640Ssam {
99313640Ssam char mbuf[200];
99413640Ssam
99513640Ssam if (!opt)
99613640Ssam return;
99713640Ssam sprintf(mbuf, "%s from %s!%s arrived\n", file, rmtsys, rmtuser);
99817832Sralph mailst(nuser, mbuf, CNULL);
99913640Ssam return;
100013640Ssam }
100123591Sbloom
nullf()100223591Sbloom nullf()
100323591Sbloom {
100423591Sbloom return SUCCESS;
100523591Sbloom }
1006