static char sccsid
[] = "@(#)cntrl.c 5.11 (Berkeley) %G%";
extern int gturnon(), gturnoff();
extern int grdmsg(), grddata();
extern int gwrmsg(), gwrdata();
extern int imsg(), omsg(), nullf();
extern int twrmsg(), trdmsg();
extern int twrdata(), trddata();
extern int fturnon(), fturnoff();
extern int frdmsg(), frddata();
extern int fwrmsg(), fwrdata();
't', nullf
, trdmsg
, twrmsg
, trddata
, twrdata
, nullf
,
'f', fturnon
, frdmsg
, fwrmsg
, frddata
, fwrdata
, fturnoff
,
'g', gturnon
, grdmsg
, gwrmsg
, grddata
, gwrdata
, gturnoff
,
int (*Imsg
)() = imsg
, (*Omsg
)() = omsg
;
int (*Rdmsg
)()=imsg
, (*Rddata
)();
int (*Wrmsg
)()=omsg
, (*Wrdata
)();
int (*Turnon
)()=nullf
, (*Turnoff
)() = nullf
;
struct timeb Now
, LastTurned
, LastCheckedNoLogin
;
int TransferSucceeded
= 1;
#define EM_LOCACC "N1" /* local access to file denied */
#define EM_RMTACC "N2" /* remote access to file/path denied */
#define EM_BADUUCP "N3" /* a bad uucp command was generated */
#define EM_NOTMP "N4" /* remote error - can't create temp */
#define EM_RMTCP "N5" /* can't copy to remote directory - file in public */
#define EM_LOCCP "N6" /* can't copy on local system */
"COPY FAILED (reason not given by remote)",
"local access to file denied",
"remote access to path/file denied",
"system error - bad uucp command generated",
"remote system can't create temp file",
"can't copy to file/directory - file left in PUBDIR/user/file",
"can't copy to file/directory on local system - file left in PUBDIR/user/file"
#define XUUCP 'X' /* execute uucp (string) */
#define SLTPTCL 'P' /* select protocol (string) */
#define USEPTCL 'U' /* use protocol (character) */
#define RCVFILE 'R' /* receive file (string) */
#define SNDFILE 'S' /* send file (string) */
#define RQSTCMPT 'C' /* request complete (string - yes | no) */
#define HUP 'H' /* ready to hangup (string - yes | no) */
#define RESET 'X' /* reset line modes */
#define W_FILE1 wrkvec[1]
#define W_FILE2 wrkvec[2]
#define W_OPTNS wrkvec[4]
#define W_DFILE wrkvec[5]
#define W_NUSER wrkvec[7]
#define RMESG(m, s, n) if (rmesg(m, s, n) != 0) {(*Turnoff)(); return FAIL;} else
#define RAMESG(s, n) if (rmesg('\0', s, n) != 0) {(*Turnoff)(); return FAIL;} else
#define WMESG(m, s) if(wmesg(m, s) != 0) {(*Turnoff)(); return FAIL;} else
char Wfile
[MAXFULLNAME
] = {'\0'};
* To avoid a huge backlog of X. files, start uuxqt every so often.
static int nXfiles
= 0; /* number of X files since last uuxqt start */
static char send_or_receive
;
* cntrl - this routine will execute the conversation
* between the two machines after both programs are
char msg
[BUFSIZ
], rqstr
[BUFSIZ
];
char filename
[MAXFULLNAME
], wrktype
, *wrkvec
[20];
extern (*Rdmsg
)(), (*Wrmsg
)();
extern char *index(), *lastpart();
static int pnum
, tmpnum
= 0;
for (i
= 0; i
< sizeof wrkvec
/ sizeof wrkvec
[0]; i
++)
DEBUG(4, "*** TOP *** - role=%s\n", role
? "MASTER" : "SLAVE");
if (Now
.time
> (LastCheckedNoLogin
.time
+60)) {
LastCheckedNoLogin
= Now
;
if (access(NOLOGIN
, 0) == 0) {
logent(NOLOGIN
, "UUCICO SHUTDOWN");
logent("DEBUGGING", "continuing anyway");
if (ReverseRole
|| (narg
= gtwvec(Wfile
, Spool
, wkpre
, wrkvec
)) == 0) {
for (i
= 1; i
< narg
; i
++) {
sprintf(rqstr
, "X %s", msg
);
logent(rqstr
, "REQUEST");
mailopt
= index(W_OPTNS
, 'm') != NULL
;
ntfyopt
= index(W_OPTNS
, 'n') != NULL
;
if (narg
< 5 || W_TYPE
[1] != '\0') {
bnp
= rindex(Wfile
, '/');
sprintf(rqstr
, "%s/%s", CORRUPT
, bnp
? bnp
+ 1 : Wfile
);
syslog(LOG_WARNING
, "%s CORRUPTED: %d args", Wfile
,
sprintf(User
, "%.9s", W_USER
);
sprintf(rqstr
, "%s %s %s %s", W_TYPE
, W_FILE1
,
logent(rqstr
, "REQUEST");
if (wrktype
== SNDFILE
) {
strcpy(filename
, W_FILE1
);
DEBUG(4, "expfile type - %d, ", i
);
if (i
!= 0 && chkpth(User
, "", filename
))
if (index(W_OPTNS
, 'c') == NULL
) {
fp
= fopen(subfile(Dfile
), "r");
(fp
= fopen(subfile(filename
), "r")) == NULL
) {
/* can not read data file */
logent("CAN'T READ DATA", _FAILED
);
TransferSucceeded
= 1; /* else will keep sending */
lnotify(User
, filename
, "can't access");
/* if file exists but is not generally readable... */
if (i
!= 0 && fstat(fileno(fp
), &stbuf
) == 0
&& (stbuf
.st_mode
& ANYREAD
) == 0) {
TransferSucceeded
= 1; /* else will keep sending */
logent("DENIED", "ACCESS");
lnotify(User
, filename
, "access denied");
if (wrktype
== RCVFILE
) {
strcpy(filename
, W_FILE2
);
if (chkpth(User
, "", filename
)
|| chkperm(filename
, index(W_OPTNS
, 'd'))) {
logent("DENIED", "ACCESS");
TransferSucceeded
= 1; /* else will keep trying */
lnotify(User
, filename
, "access denied");
sprintf(Dfile
, "%s/TM.%05d.%03d", Spool
, pnum
, tmpnum
++);
if ((fp
= fopen(subfile(Dfile
), "w")) == NULL
) {
/* can not create temp */
logent("CAN'T CREATE TM", _FAILED
);
DEBUG(4, "wrktype - %c\n", wrktype
);
willturn
= msg
[0] == HUP
;
DEBUG(4, "PROCESS: msg - %s\n", msg
);
DEBUG(4, "RQSTCMPT:\n", CNULL
);
logent(Em_msg
[i
], "REQUEST FAILED");
TransferSucceeded
= 1; /* He had his chance */
notify(mailopt
, W_USER
, W_FILE1
, Rmtname
, &msg
[1]);
if (msg
[2] == 'M' && role
== MASTER
) {
logent(Rmtname
, "TURNAROUND");
Nfiles
= 0; /* force rescan of queue for work */
DEBUG(4, "HUP:\n", CNULL
);
syslog(LOG_ERR
, "Wrong Role - HUP");
if (!iswrk(Wfile
, "chk", Spool
, wkpre
)) {
* want to create an orphan uuxqt,
* so a double-fork is needed.
i
= getargs(msg
, wrkvec
, 20);
strcpy(filename
, W_FILE1
);
if (index(filename
, ';') != NULL
|| index(W_FILE2
, ';') != NULL
if (chkpth("", Rmtname
, filename
)) {
logent("XUUCP DENIED", filename
);
sprintf(rqstr
, "%s %s", filename
, W_FILE2
);
/* MASTER section of SNDFILE */
DEBUG(4, "%s\n", "SNDFILE:");
logent(Em_msg
[i
], "REQUEST FAILED");
/* dont send him files he can't save */
if (strcmp(&msg
[1], EM_NOTMP
) == 0) {
notify(mailopt
, W_USER
, W_FILE1
, Rmtname
, &msg
[1]);
syslog(LOG_ERR
, "Wrong Role - SN");
syslog(LOG_ERR
, "Wrong Role - SY");
if (fstat(fileno(fp
), &stbuf
) < 0) {
syslog(LOG_ERR
, "stat(%s) failed: %m",filename
);
i
= 1 + (int)(stbuf
.st_size
/ XFRRATE
);
if (send_or_receive
!= SNDFILE
) {
send_or_receive
= SNDFILE
;
systat(Rmtname
, SS_INPROGRESS
, "SENDING");
ret
= (*Wrdata
)(fp
, Ofn
);
/* SLAVE section of SNDFILE */
syslog(LOG_ERR
, "Wrong Role - SLAVE");
/* request to receive file */
i
= getargs(msg
, wrkvec
, 20);
bnp
= rindex(Wfile
, '/');
sprintf(rqstr
, "%s/%s", CORRUPT
, bnp
? bnp
+ 1 : Wfile
);
syslog(LOG_WARNING
, "%s CORRUPTED: %d args", Wfile
, i
);
sprintf(rqstr
, "%s %s %s %s", W_TYPE
, W_FILE1
, W_FILE2
, W_USER
);
logent(rqstr
, "REQUESTED");
DEBUG(4, "msg - %s\n", msg
);
strcpy(filename
, W_FILE2
);
/* Run uuxqt occasionally */
if (filename
[0] == XQTPRE
) {
* want to create an orphan uuxqt,
* so a double-fork is needed.
/* expand filename, i is set to 0 if this is
* is a vanilla spool file, so no stat(II)s are needed */
DEBUG(4, "expfile type - %d\n", i
);
if (chkpth("", Rmtname
, filename
)
|| chkperm(filename
, index(W_OPTNS
, 'd'))) {
WMESG(SNDFILE
, EM_RMTACC
);
logent("DENIED", "PERMISSION");
strcat(filename
, lastpart(W_FILE1
));
sprintf(User
, "%.9s", W_USER
);
DEBUG(4, "chkpth ok Rmtname - %s\n", Rmtname
);
/* speed things up by OKing file before
* creating TM file. If the TM file cannot be created,
* then the conversation bombs, but that seems reasonable,
* as there are probably serious problems then.
sprintf(Dfile
, "%s/TM.%05d.%03d", Spool
, pnum
, tmpnum
++);
if((fp
= fopen(subfile(Dfile
), "w")) == NULL
) {
/* WMESG(SNDFILE, EM_NOTMP);*/
logent("CAN'T OPEN", "TM FILE");
if (send_or_receive
!= RCVFILE
) {
send_or_receive
= RCVFILE
;
systat(Rmtname
, SS_INPROGRESS
, "RECEIVING");
ret
= (*Rddata
)(Ifn
, fp
);
if (ferror(fp
) || fclose(fp
))
/* copy to user directory */
ntfyopt
= index(W_OPTNS
, 'n') != NULL
;
status
= xmv(Dfile
, filename
);
if (willturn
&& Now
.time
> (LastTurned
.time
+turntime
)
&& iswrk(Wfile
, "chk", Spool
, wkpre
)) {
WMESG(RQSTCMPT
, status
? EM_RMTCP
: "YM");
WMESG(RQSTCMPT
, status
? EM_RMTCP
: YES
);
; /* vanilla file, nothing to do */
if (W_MODE
== 0 || sscanf(W_MODE
, "%o", &filemode
) != 1)
chmod(subfile(filename
), (filemode
|BASEMODE
)&0777);
arrived(ntfyopt
, filename
, W_NUSER
, Rmtname
, User
);
status
= putinpub(filename
, Dfile
, W_USER
);
DEBUG(4, "->PUBDIR %d\n", status
);
arrived(ntfyopt
, filename
, W_NUSER
, Rmtname
, User
);
/* MASTER section of RCVFILE */
DEBUG(4, "%s\n", "RCVFILE:");
logent(Em_msg
[i
], "REQUEST FAILED");
notify(mailopt
, W_USER
, W_FILE1
, Rmtname
, &msg
[1]);
syslog(LOG_ERR
, "Wrong Role - RN");
syslog(LOG_ERR
, "Wrong Role - RY");
if (send_or_receive
!= RCVFILE
) {
send_or_receive
= RCVFILE
;
systat(Rmtname
, SS_INPROGRESS
, "RECEIVING");
ret
= (*Rddata
)(Ifn
, fp
);
if (ferror(fp
) || fclose(fp
))
/* copy to user directory */
strcat(filename
, lastpart(W_FILE1
));
status
= xmv(Dfile
, filename
);
WMESG(RQSTCMPT
, status
? EM_RMTCP
: YES
);
notify(mailopt
, W_USER
, filename
, Rmtname
,
status
? EM_LOCCP
: YES
);
sscanf(&msg
[2], "%o", &filemode
);
chmod(subfile(filename
), (filemode
|BASEMODE
)&0777);
putinpub(filename
, Dfile
, W_USER
);
if (msg
[strlen(msg
)-1] == 'M') {
logent(Rmtname
, "TURNAROUND");
Nfiles
= 0; /* force rescan of queue for work */
/* SLAVE section of RCVFILE */
syslog(LOG_ERR
, "Wrong Role - SLAVE RCV");
/* request to send file */
logent(rqstr
, "REQUESTED");
i
= getargs(msg
, wrkvec
, 20);
bnp
= rindex(Wfile
, '/');
sprintf(rqstr
, "%s/%s", CORRUPT
, bnp
? bnp
+ 1 : Wfile
);
syslog(LOG_WARNING
, "%s CORRUPTED: %d args", Wfile
, i
);
DEBUG(4, "msg - %s\n", msg
);
DEBUG(4, "W_FILE1 - %s\n", W_FILE1
);
strcpy(filename
, W_FILE1
);
strcat(filename
, lastpart(W_FILE2
));
sprintf(User
, "%.9s", W_USER
);
if (chkpth("", Rmtname
, filename
) || anyread(filename
)) {
WMESG(RCVFILE
, EM_RMTACC
);
logent("DENIED", "PERMISSION");
DEBUG(4, "chkpth ok Rmtname - %s\n", Rmtname
);
if ((fp
= fopen(subfile(filename
), "r")) == NULL
) {
WMESG(RCVFILE
, EM_RMTACC
);
logent("CAN'T OPEN", "DENIED");
if (fstat(fileno(fp
), &stbuf
) < 0) {
syslog(LOG_ERR
, "stat(%s) failed: %m", filename
);
i
= 1 + (int)(stbuf
.st_size
/ XFRRATE
);
if (willturn
&& Now
.time
> (LastTurned
.time
+turntime
)
&& iswrk(Wfile
, "chk", Spool
, wkpre
)) {
sprintf(msg
, "%s %o%s", YES
, (int)stbuf
.st_mode
& 0777,
willturn
< 0 ? " M" : "");
if (send_or_receive
!= SNDFILE
) {
send_or_receive
= SNDFILE
;
systat(Rmtname
, SS_INPROGRESS
, "SENDING");
ret
= (*Wrdata
)(fp
, Ofn
);
* read message 'c'. try 'n' times
* return code: SUCCESS | FAIL
DEBUG(4, "rmesg - '%c' ", c
);
while ((*Rdmsg
)(msg
, Ifn
) != SUCCESS
) {
DEBUG(4, "got FAIL\n", CNULL
);
sprintf(str
, "expected '%c' got FAIL (%d)", c
, errno
);
sprintf(str
, "expected ANY got FAIL (%d)", errno
);
if (c
!= '\0' && msg
[0] != c
) {
DEBUG(4, "got %s\n", msg
);
sprintf(str
, "expected '%c' got %s", c
, msg
);
DEBUG(4, "got %s\n", msg
);
* write a message (type m)
* return codes: SUCCESS - ok | FAIL - ng
DEBUG(4, "wmesg '%c' ", m
);
return (*Wrmsg
)(m
, s
, Ofn
);
* mail results of command
notify(mailopt
, user
, file
, sys
, msgcode
)
char *user
, *file
, *sys
, *msgcode
;
if (!mailopt
&& *msgcode
== 'Y')
sprintf(str
, "file %s!%s -- %s\n",
mailst(user
, str
, CNULL
);
lnotify(user
, file
, mesg
)
char *user
, *file
, *mesg
;
sprintf(mbuf
, "file %s!%s -- %s\n", Myname
, file
, mesg
);
mailst(user
, mbuf
, CNULL
);
* converse with the remote machine, agree upon a protocol (if possible)
* and start the protocol.
* SUCCESS - successful protocol selection
* FAIL - can't find common or open failed
extern (*Rdmsg
)(), (*Wrmsg
)();
extern char *blptcl(), fptcl();
char msg
[BUFSIZ
], str
[MAXFULLNAME
];
if ((str
[0] = fptcl(&msg
[1])) == NULL
) {
DEBUG(4, "protocol %s\n", str
);
WMESG(SLTPTCL
, blptcl(str
));
if (stptcl(&msg
[1]) != 0)
DEBUG(4, "Protocol %s\n", msg
);
* choose a protocol from the input string (str) and return the it
* '\0' - no acceptable protocol
* any character - the chosen protocol
register struct Proto
*p
;
for (p
= Ptbl
; p
->P_id
!= '\0'; p
++) {
/* Only use 't' on TCP/IP */
if (p
->P_id
== 't' && strcmp("TCP", LineType
))
/* only use 'f' protocol on PAD */
if (p
->P_id
== 'f' && strcmp("PAD", LineType
))
if (index(str
, p
->P_id
) != NULL
) {
* build a string of the letters of the available protocols
register struct Proto
*p
;
for (p
= Ptbl
, s
= str
; (*s
++ = p
->P_id
) != '\0'; p
++)
* this routine will set up the six routines
* (Rdmsg, Wrmsg, Rddata, Wrdata, Turnon, Turnoff) for the
* FAIL - no find or failed to open
register struct Proto
*p
;
for (p
= Ptbl
; p
->P_id
!= '\0'; p
++) {
/* found protocol - set routines */
if ((*Turnon
)() != SUCCESS
)
DEBUG(4, "Proto started %c\n", *c
);
DEBUG(4, "Proto start-fail %c\n", *c
);
* put file in public place. if successful, filename is modified
* return code SUCCESS | FAIL
putinpub(file
, tmp
, user
)
register char *file
, *tmp
, *user
;
char fullname
[MAXFULLNAME
];
sprintf(fullname
, "%s/%s/", PUBDIR
, user
);
if (mkdirs(fullname
) != 0) {
/* can not make directories */
DEBUG(1, "Cannot mkdirs(%s)\n", fullname
);
strcat(fullname
, lastpart(file
));
status
= xmv(tmp
, fullname
);
chmod(subfile(fullname
), BASEMODE
);
* notify receiver of arrived file
arrived(opt
, file
, nuser
, rmtsys
, rmtuser
)
char *file
, *nuser
, *rmtsys
, *rmtuser
;
sprintf(mbuf
, "%s from %s!%s arrived\n", file
, rmtsys
, rmtuser
);
mailst(nuser
, mbuf
, CNULL
);