Home | History | Annotate | Download | only in bnu
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License, Version 1.0 only
      6  * (the "License").  You may not use this file except in compliance
      7  * with the License.
      8  *
      9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
     10  * or http://www.opensolaris.org/os/licensing.
     11  * See the License for the specific language governing permissions
     12  * and limitations under the License.
     13  *
     14  * When distributing Covered Code, include this CDDL HEADER in each
     15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     16  * If applicable, add the following below this CDDL HEADER, with the
     17  * fields enclosed by brackets "[]" replaced with your own identifying
     18  * information: Portions Copyright [yyyy] [name of copyright owner]
     19  *
     20  * CDDL HEADER END
     21  */
     22 /*
     23  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
     24  * Use is subject to license terms.
     25  */
     26 
     27 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
     28 /*	  All Rights Reserved  	*/
     29 
     30 
     31 #pragma ident	"%Z%%M%	%I%	%E% SMI"
     32 
     33 #include "uucp.h"
     34 #include "log.h"
     35 
     36 void notify(), lnotify(), unlinkdf(), arrived();
     37 static void stmesg();
     38 static int nospace();
     39 
     40 struct Proto {
     41 	char P_id;
     42 	int (*P_turnon)();
     43 	int (*P_rdmsg)();
     44 	int (*P_wrmsg)();
     45 	int (*P_rddata)();
     46 	int (*P_wrdata)();
     47 	int (*P_turnoff)();
     48 };
     49 
     50 extern char _Protocol[];
     51 extern char *findProto();
     52 
     53 extern char uuxqtarg[];
     54 
     55 extern int gturnon(), gturnoff();
     56 extern int grdmsg(), grddata();
     57 extern int gwrmsg(), gwrdata();
     58 
     59 extern int wmesg(), rmesg(), expfile(), putinpub(), stptcl();
     60 extern void setline(), TMname(), cleanup(), pfEndfile(), statlog(), mailst();
     61 
     62 #ifdef	D_PROTOCOL
     63 extern int dturnon(), dturnoff();
     64 extern int drdmsg(), drddata();
     65 extern int dwrmsg(), dwrdata();
     66 #endif	/* D_PROTOCOL */
     67 
     68 #ifdef	X_PROTOCOL
     69 extern int xturnon(), xturnoff();
     70 extern int xrdmsg(), xrddata();
     71 extern int xwrmsg(), xwrdata();
     72 #endif	/* X_PROTOCOL */
     73 
     74 #ifdef E_PROTOCOL
     75 extern int eturnon(), eturnoff();
     76 extern int erdmsg(), erddata();
     77 extern int ewrmsg(), ewrdata();
     78 extern int trdmsg(), twrmsg();
     79 extern int trddata(), twrdata();
     80 #endif /* E_PROTOCOL */
     81 
     82 #ifdef F_PROTOCOL
     83 extern int fturnon(), fturnoff();
     84 extern int frdmsg(), frddata();
     85 extern int fwrmsg(), fwrdata();
     86 #endif	/* F_PROTOCOL */
     87 
     88 extern int imsg();
     89 extern int omsg();
     90 extern int turnoff();
     91 extern long strtol();
     92 
     93 struct Proto Ptbl[]={
     94 	{'g', gturnon, grdmsg, gwrmsg, grddata, gwrdata, gturnoff},
     95 	{'G', gturnon, grdmsg, gwrmsg, grddata, gwrdata, gturnoff},
     96 
     97 #ifdef E_PROTOCOL
     98 	{'e', eturnon, erdmsg, ewrmsg, erddata, ewrdata, eturnoff},
     99 	{'t', eturnon, trdmsg, twrmsg, trddata, twrdata, eturnoff},
    100 #endif /* E_PROTOCOL */
    101 
    102 #ifdef	D_PROTOCOL
    103 	{'d', dturnon, drdmsg, dwrmsg, drddata, dwrdata, dturnoff},
    104 #endif	/* D_PROTOCOL */
    105 
    106 #ifdef	X_PROTOCOL
    107 	{'x', xturnon, xrdmsg, xwrmsg, xrddata, xwrdata, xturnoff},
    108 #endif	/* X_PROTOCOL */
    109 
    110 #ifdef	F_PROTOCOL
    111 	{'f', fturnon, frdmsg, fwrmsg, frddata, fwrdata, fturnoff},
    112 #endif	/* F_PROTOCOL */
    113 	'\0'
    114 };
    115 
    116 #define VALIDSIZE sizeof(Ptbl)/sizeof(struct Proto)
    117 
    118 int (*Rdmsg)()=imsg, (*Rddata)();
    119 int (*Wrmsg)()=omsg, (*Wrdata)();
    120 int (*Turnon)(), (*Turnoff)()=turnoff;
    121 
    122 
    123 #define YES "Y"
    124 #define NO "N"
    125 
    126 #define TBUFSIZE	128	/* temporary buffer size */
    127 #define FLENRADIX	(16)	/* output radix for file start point */
    128 
    129 /*
    130  * failure messages
    131  */
    132 #define EM_MAX		10
    133 #define EM_LOCACC	"N1"	/* local access to file denied */
    134 #define EM_RMTACC	"N2"	/* remote access to file/path denied */
    135 #define EM_BADUUCP	"N3"	/* a bad uucp command was generated */
    136 #define EM_NOTMP	"N4"	/* remote error - can't create temp */
    137 #define EM_RMTCP	"N5"	/* can't copy to remote directory - file in public */
    138 #define EM_LOCCP	"N6"	/* can't copy on local system */
    139 #define EM_SEEK		"N7"	/* can't seek to checkpoint */
    140 /* 	EM_		"N8" */	/* placeholder*/
    141 /* 	EM_		"N9" */	/* placeholder*/
    142 #define EM_ULIMIT	"N10"	/* receiver ulimit exceeded */
    143 
    144 char *Em_msg[] = {
    145 	"COPY FAILED (reason not given by remote)",
    146 	"local access to file denied",
    147 	"remote access to path/file denied",
    148 	"system error - bad uucp command generated",
    149 	"remote system can't create temp file",
    150 	"can't copy to file/directory - file left in PUBDIR/user/file",
    151 	"can't copy to file/directory - file left in PUBDIR/user/file",
    152 	"can't seek to checkpoint",
    153 	"COPY FAILED (reason not given by remote)", /* placeholder */
    154 	"COPY FAILED (reason not given by remote)", /* placeholder */
    155 	"file exceeds ulimit of receiving system",
    156 	"forwarding error"
    157 };
    158 
    159 
    160 #define XUUCP 'X'	/* execute uucp (string) */
    161 #define SLTPTCL 'P'	/* select protocol  (string)  */
    162 #define USEPTCL 'U'	/* use protocol (character) */
    163 #define RCVFILE 'R'	/* receive file (string) */
    164 #define SNDFILE 'S'	/* send file (string) */
    165 #define RQSTCMPT 'C'	/* request complete (string - yes | no) */
    166 #define HUP     'H'	/* ready to hangup (string - yes | no) */
    167 #define RESET	'X'	/* reset line modes */
    168 
    169 #define W_MAX		10	/* maximum number of C. files per line */
    170 #define W_MIN		7	/* min number of entries */
    171 #define W_TYPE		wrkvec[0]
    172 #define W_FILE1		wrkvec[1]
    173 #define W_FILE2		wrkvec[2]
    174 #define W_USER		wrkvec[3]
    175 #define W_OPTNS		wrkvec[4]
    176 #define W_DFILE		wrkvec[5]
    177 #define W_MODE		wrkvec[6]
    178 #define W_NUSER		wrkvec[7]
    179 #define W_SFILE		wrkvec[8]
    180 #define W_RDFILE	wrkvec[8]
    181 #define W_POINT		wrkvec[9]
    182 #define W_FSIZE		wrkvec[9]
    183 #define W_RFILE		wrkvec[5]
    184 #define W_XFILE		wrkvec[5]
    185 char	*mf;
    186 
    187 #define RMESG(m, s) if (rmesg(m, s) != 0) {(*Turnoff)(); return(FAIL);}
    188 #define RAMESG(s) if (rmesg('\0', s) != 0) {(*Turnoff)(); return(FAIL);}
    189 #define WMESG(m, s) if(wmesg(m, s) != 0) {(*Turnoff)(); return(FAIL);}
    190 
    191 char Wfile[MAXFULLNAME] = {'\0'};
    192 char Dfile[MAXFULLNAME];
    193 
    194 char	*wrkvec[W_MAX+1];
    195 int	statfopt;
    196 
    197 /*
    198  * Create restart point filename
    199  */
    200 
    201 static void
    202 Pname(fileid, dfile, direct)
    203   char *fileid;
    204   char *dfile;
    205   int  direct;		/* indicates a direct delivery temp file nameneeded */
    206 {
    207     char *p;
    208 
    209 	    /*
    210 	     * If the file is direct delivery, then its name is:
    211 	     *
    212 	     *		/dir/dir/dir/.Pnnnnnnnn
    213 	     *
    214 	     * in the target directory.  We create this by replacing the
    215 	     * name of the target file with the D.nnnnnn name from the
    216 	     * work vector, and then overwriting the D. with .P
    217 	     */
    218 
    219 	    if (direct) {
    220 		if (p = strrchr(dfile, '/')) {	/* find the last slash */
    221 			p++;
    222 			strcpy(p, fileid);	/* append D.nnnnn name to dir */
    223 			*p++ = '.';
    224 			*p = 'P';		/* replace beginning with .P */
    225 	    		DEBUG(7, "Point file (direct) =%s\n", dfile);
    226 			return;
    227 		}
    228 	    }
    229 	    strcpy(dfile, RemSpool);
    230 	    strcat(dfile, "/");
    231 	    p = dfile + strlen(Dfile);
    232 	    strcat(dfile, fileid);
    233 	    *p = 'P';
    234 	    DEBUG(7, "Point file=%s\n", dfile);
    235 	return;
    236 }
    237 
    238 
    239 /*
    240  * execute the conversation between the two machines
    241  * after both programs are running.
    242  * returns:
    243  *	SUCCESS 	-> ok
    244  *	FAIL 		-> failed
    245  */
    246 int
    247 cntrl()
    248 {
    249 	FILE * fp;
    250 	struct stat stbuf;
    251 	char *	p;
    252 	long 	startp;		/* checkpoint restart point */
    253 	long	actualsize;	/* actual file size */
    254 	long	im;
    255 	long	lfilemode;
    256 	mode_t	filemode;
    257 	int	status;
    258 	int	i, narg;
    259 	int	mailopt, ntfyopt;
    260 	int	ret;
    261 	char	tbuf[TBUFSIZE];
    262 	char	rqstr[BUFSIZ];	/* contains the current request message */
    263 	char	msg[BUFSIZ];
    264 	char	filename[MAXFULLNAME], wrktype;
    265 	char	fsize[NAMESIZE];	/* holds file size/checkpoint string */
    266 	char	localname[MAXFULLNAME];	/* real local system name */
    267 	char	Recspool[MAXFULLNAME];	/* spool area for slave uucico */
    268 	static pid_t	pnum;
    269 	extern int uuxqtflag;	/* set if received X. or D. file */
    270 
    271 	pnum = getpid();
    272 	Wfile[0] = '\0';
    273 	(void) sprintf(Recspool, "%s/%s", SPOOL, Rmtname);
    274 top:
    275 	(void) strcpy(User, Uucp);
    276 	statfopt = 0;
    277 	*Jobid = '\0';
    278 	DEBUG(4, "*** TOP ***  -  Role=%d, ", Role);
    279 	setline(RESET);
    280 	if (Role == MASTER) {
    281 
    282 		/*
    283 		 * get work
    284 		 */
    285 		pfFindFile();
    286 		if ((narg = gtwvec(Wfile, wrkvec, W_MAX)) == 0) {
    287 			acEnd(COMPLETE); /*stop collecting accounting log */
    288 			WMESG(HUP, ""); /* I(master) am done. want me to quit? */
    289 			RMESG(HUP, msg);
    290 			goto process;
    291 		}
    292 		DEBUG(7, "Wfile - %s,", Wfile);
    293 		strncpy(Jobid, BASENAME(Wfile, '/')+2, NAMESIZE);
    294 		Jobid[NAMESIZE-1] = '\0';
    295 		DEBUG(7, "Jobid = %s\n", Jobid);
    296 		wrktype = W_TYPE[0];
    297 		pfFound(Jobid, W_OPTNS, Nstat.t_qtime);
    298 		mailopt = strchr(W_OPTNS, 'm') != NULL;
    299 		statfopt = strchr(W_OPTNS, 'o') != NULL;
    300 		ntfyopt = strchr(W_OPTNS, 'n') != NULL;
    301 
    302 		uucpname(localname); /* get real local machine name */
    303 		acDojob(Jobid, localname, W_USER);
    304 		scRequser(W_USER); /* log requestor user id */
    305 
    306 		/*
    307 		 * We used to check for corrupt workfiles here (narg < 5),
    308 		 * but we were doing it wrong, and besides, anlwrk.c is the
    309 		 * appropriate place to do it.
    310 		 */
    311 
    312 		(void) sprintf(User, "%s", W_USER);
    313 		if (wrktype == SNDFILE ) {
    314 			(void) sprintf(rqstr, "%s!%s --> %s!%s (%s)", Myname,
    315 			    W_FILE1, Rmtname, W_FILE2, User);
    316 
    317 			/* log destination node, user and file name */
    318 
    319 			scDest(Rmtname,NOTAVAIL,W_FILE2);
    320 
    321 			/* log source node, file owner, file name, mod time and size */
    322 
    323 			scSrc(Myname,scOwn(W_FILE1),W_FILE1,scMtime(W_FILE1)
    324 						,scSize(W_FILE1));
    325 
    326 			logent(rqstr, "REQUEST");
    327 			CDEBUG(1, "Request: %s\n", rqstr);
    328 			mf = W_SFILE;
    329 			(void) strcpy(filename, W_FILE1);
    330 			expfile(filename);
    331 			(void) strcpy(Dfile, W_DFILE);
    332 			if ( (fp = fopen(Dfile, "r")) == NULL) {
    333 			    if ( (fp = fopen(filename, "r")) == NULL) {
    334 				/*  cannot read spool or original file */
    335 				unlinkdf(Dfile);
    336 				lnotify(User, rqstr, "can't access");
    337 				(void) sprintf(msg, "CAN'T READ %s %d",
    338 					filename, errno);
    339 				logent(msg, "FAILED");
    340 				CDEBUG(1, "Failed: Can't Read %s\n", filename);
    341 		    		scWrite();	/* log the security violation */
    342 				goto top;
    343 			    } else {
    344 				/* ensure original file is publicly readable */
    345 				if ( !F_READANY(fileno(fp)) ) {
    346 				    /* access denied */
    347 				    logent("DENIED", "ACCESS");
    348 				    unlinkdf(W_DFILE);
    349 				    lnotify(User, rqstr, "access denied");
    350 				    CDEBUG(1, "Failed: Access Denied\n%s", "");
    351 		    		    scWrite();	/* log the security violation */
    352 				    goto top;
    353 				}
    354 			    }
    355 			}
    356 
    357 			if (Restart && !(fstat(fileno(fp), &stbuf))) {
    358 				(void) sprintf(fsize, "0x%lx", stbuf.st_size);
    359 				W_FSIZE = fsize; /* set file size in vector */
    360 			}
    361 
    362 			/* Check whether remote's ulimit is exceeded */
    363 			if (SizeCheck) {
    364 				if (((stbuf.st_size-1)/512 + 1) > RemUlimit) {
    365 					/* remote ulimit exceeded */
    366 					unlinkdf(Dfile);
    367 					lnotify(User, rqstr, "remote ulimit exceeded");
    368 					logent("DENIED", "REMOTE ULIMIT EXCEEDED");
    369 					CDEBUG(1, "Denied: remote ulimit exceeded %s\n", filename);
    370 					scWrite();
    371 					(void) fclose(fp);
    372 					goto top;
    373 				}
    374 			}
    375 		}
    376 
    377 		if (wrktype == RCVFILE) {
    378 			(void) sprintf(rqstr, "%s!%s --> %s!%s (%s)", Rmtname,
    379 			    W_FILE1, Myname, W_FILE2, User);
    380 
    381 			/* log destination node, user and file name */
    382 
    383 			scDest(Myname,NOTAVAIL,W_FILE2);
    384 
    385 			/* log source node, file owner, file name, mod time and size */
    386 
    387 			scSrc(Rmtname,NOTAVAIL,W_FILE1,NOTAVAIL,NOTAVAIL);
    388 
    389 			logent(rqstr, "REQUEST");
    390 			CDEBUG(1, "Request: %s\n", rqstr);
    391 			mf = W_RFILE;
    392 			(void) strcpy(filename, W_FILE2);
    393 
    394 			/* change Wrkdir to SPOOL/Rmtname in case the file being
    395 			** requested is needed for some remote execution.
    396 			*/
    397 
    398 			(void) strcpy(Wrkdir, Recspool);
    399 			expfile(filename);
    400 
    401 			/* now change Wrkdir back to what it was
    402 			** just being paranoid.
    403 			*/
    404 
    405 			(void) strcpy(Wrkdir, RemSpool);
    406 			if (chkperm(W_FILE1, filename, strchr(W_OPTNS, 'd'))) {
    407 
    408 				/* access denied */
    409 				logent("DENIED", "ACCESS");
    410 				lnotify(User, rqstr, "access denied");
    411 				CDEBUG(1, "Failed: Access Denied--File: %s\n",
    412 				    filename);
    413 		    		scWrite();	/* log the security violation */
    414 				goto top;
    415 			}
    416 
    417 			/*
    418 			 * If we are not going to spool the file in the spool
    419 			 * directory, just use the destination file name.  If we
    420 			 * are not supporting restart, wipe out the target file.
    421 			 * else:
    422 			 *
    423 			 * If restart is enabled, make up the Point file name
    424 			 * as the file to open, else use the TM style name.
    425 			 *
    426 			 * If we run into a spool name of "D.0", this implies
    427 			 * that someone forgot to install the new uucp and
    428 			 * uux commands.  Such jobs will not be checkpointed.
    429 			 */
    430 
    431 
    432 			if (Restart && (strlen(W_RDFILE) > (size_t) 6)) {
    433 				if (noSpool()) {
    434 				    strcpy(Dfile, filename);	/* use Dest file directly */
    435 				    Pname(W_RDFILE, Dfile, TRUE);
    436 				}
    437 				else
    438 				    Pname(W_RDFILE, Dfile, FALSE);
    439 			}
    440 			else {
    441 			    TMname(Dfile, pnum); /* get TM file name */
    442 			    unlink(Dfile);
    443 			}
    444 
    445 			/*
    446 			 * If the spool file exists, it better have the right owner
    447 			 * and permissions!
    448 			 */
    449 
    450 			if (Restart && noSpool()) {
    451 				if ((! stat(Dfile, &stbuf)) &&
    452 				    ((stbuf.st_mode != (DFILEMODE|S_IFREG)) ||
    453 				    ((stbuf.st_gid != UUCPGID) ||
    454 				     (stbuf.st_uid != UUCPUID)))) {
    455 				    lnotify(User, rqstr,
    456 					"bad spool file ownership/permissions");
    457 				    logent("BAD DESTFILE OWNER/PERMS", "FAIL");
    458 				    CDEBUG(1, "Failed: bad dest file owner/perms 0%o; fail\n", stbuf.st_mode);
    459 				    goto top;
    460 				}
    461 			}
    462 			if ( ((fp = fopen(Dfile, "a+")) == NULL)
    463 			     || nospace(Dfile)) {
    464 
    465 				/* can not create temp */
    466 				if (noSpool())
    467 				    logent("CAN'T CREATE/OPEN DEST FILE", "FAILED");
    468 				else
    469 				    logent("CAN'T CREATE TM FILE", "FAILED");
    470 				CDEBUG(1, "Failed: No Space!\n%s", "");
    471 				unlinkdf(Dfile);
    472 				assert(Ct_CREATE, Dfile, nospace(Dfile),
    473 				    __FILE__, __LINE__);
    474 				cleanup(FAIL);
    475 			}
    476 
    477 			/*
    478 			 * Send the W_POINT value to the other side.
    479 			 */
    480 
    481 			if (Restart) {
    482 			    if (fstat (fileno(fp), &stbuf)) {
    483 				logent("CAN'T STAT DFILE", "START FROM BEGINNING");
    484 				stbuf.st_size = 0L;
    485 			    }
    486 
    487 			    /*
    488 			     * find a good start point.  Take care of simple
    489 			     * underflow and the signed nature of longs.
    490 			     */
    491 
    492 			    DEBUG(7, "Dfile length 0x%lx\n", stbuf.st_size);
    493 			    startp = stbuf.st_size - (stbuf.st_size % BUFSIZ);
    494 			    if((stbuf.st_size >= 0) && (startp < 0))
    495 				startp = 0;
    496 
    497 			    if(startp)
    498 			    {
    499 				if(startp < 0)
    500 				    sprintf(tbuf,"start=0x%lx", startp);
    501 				else
    502 				    sprintf(tbuf,"start=%ld", startp);
    503 
    504 				logent(tbuf, "RESTART");
    505 			    }
    506 
    507 			    sprintf(fsize, "0x%lx", startp);
    508 			    W_POINT = fsize; /* set start point in vector */
    509 			    if (lseek(fileno(fp), startp, 0) == -1) {
    510 				WMESG(SNDFILE, EM_SEEK);
    511 				logent("CAN'T SEEK", "DENIED");
    512 				CDEBUG(1, "Failed, Can't seek in Dfile\n%s", "");
    513 				unlinkdf(Dfile);
    514 				goto top;
    515 		    	    }
    516 		    	    fp->_cnt = 0;
    517 		    	    fp->_ptr = fp->_base;
    518 			}
    519 
    520 			Seqn++;
    521 			chmod(Dfile, DFILEMODE);	/* no peeking! */
    522 			chown(Dfile, UUCPUID, UUCPGID);
    523 
    524 		}
    525 		DEBUG(4, "wrktype - %c\n ", wrktype);
    526 
    527 		/* Build up the message itself */
    528 
    529 		msg[0] = '\0';
    530 		for (i = 1; i < narg; i++) {
    531 			(void) strcat(msg, " ");
    532 			(void) strcat(msg, wrkvec[i]);
    533 		}
    534 
    535 		WMESG(wrktype, msg); /* I(master) am sending you our work file */
    536 		RMESG(wrktype, msg); /* I(master) am waiting for your response */
    537 		goto process;
    538 	}
    539 
    540 	/*
    541 	 * role is slave
    542 	 */
    543 
    544 	RAMESG(msg); /* I(slave) am waiting for our work file */
    545 
    546 process:
    547 
    548 	DEBUG(4, " PROCESS: msg - %s\n", msg);
    549 	switch (msg[0]) {
    550 
    551 	case RQSTCMPT:
    552 		DEBUG(4, "%s\n", "RQSTCMPT:");
    553 		if (msg[1] == 'N') {
    554 			i = atoi(&msg[2]);
    555 			if (i < 0 || i > EM_MAX)
    556 				i = 0;
    557 			logent(Em_msg[i], "REQUESTED");
    558 		}
    559 		if (Role == MASTER) {
    560 		        notify(mailopt, W_USER, rqstr, Rmtname, &msg[1]);
    561 		}
    562 		pfEndfile("");	/* "" indicates the file transfer completely */
    563 		goto top;
    564 
    565 	case HUP:
    566 		DEBUG(4, "%s\n", "HUP:");
    567 		if (msg[1] == 'Y') {
    568 			WMESG(HUP, YES); /* let's quit */
    569 			(*Turnoff)();
    570 			Rdmsg = imsg;
    571 			Wrmsg = omsg;
    572 			Turnoff = turnoff;
    573 			return(0);
    574 		}
    575 
    576 		if (msg[1] == 'N') {
    577 			ASSERT(Role == MASTER, Wr_ROLE, "", Role);
    578 			Role = SLAVE;
    579 			scReqsys(Rmtname); /* log requestor system */
    580 			chremdir(Rmtname);
    581 			goto top;
    582 		}
    583 
    584 		/*
    585 		 * get work
    586 		 */
    587 		if ( (switchRole() == FALSE) || !iswrk(Wfile) ) {
    588 			DEBUG(5, "SLAVE-switchRole (%s)\n",
    589 			    switchRole() ? "TRUE" : "FALSE");
    590 			WMESG(HUP, YES); /* let's quit */
    591 			RMESG(HUP, msg);
    592 			goto process;
    593 		}
    594 
    595 		/* Note that Wfile is the first C. to process at top
    596 		 * set above by iswrk() call
    597 		 */
    598 		if (uuxqtflag) {
    599 			xuuxqt(uuxqtarg);
    600 			uuxqtflag = 0;
    601 		}
    602 		WMESG(HUP, NO); /* don't quit. I(slave) have more to do */
    603 		Role = MASTER;
    604 		uucpname(localname); /* get real local machine name */
    605 		scReqsys(localname); /* log requestor system */
    606 		acInit("xfer");
    607 		goto top;
    608 
    609 	case XUUCP:
    610 		/*
    611 		 * slave part
    612 		 * No longer accepted
    613 		 */
    614 
    615 		WMESG(XUUCP, NO);
    616 		goto top;
    617 
    618 	case SNDFILE:
    619 
    620 		/*
    621 		 * MASTER section of SNDFILE
    622 		 */
    623 		DEBUG(4, "%s\n", "SNDFILE:");
    624 		if (msg[1] == 'N')
    625 		   {
    626 		    i = atoi(&msg[2]);
    627 		    if (i < 0 || i > EM_MAX)
    628 			i = 0;
    629 		    logent(Em_msg[i], "REQUEST");
    630 		    notify(mailopt, W_USER, rqstr, Rmtname, &msg[1]);
    631 		    ASSERT(Role == MASTER, Wr_ROLE, "", Role);
    632 		    (void) fclose(fp);
    633 		    /* if remote is out of tmp space, then just hang up */
    634 		    ASSERT(i != 4, Em_msg[4], Rmtname, i);	/* EM_NOTMP */
    635 		    unlinkdf(W_DFILE);
    636 		    scWrite();	/* something is wrong on other side,
    637 				   log the security violation */
    638 		    Seqn++;
    639 		    goto top;
    640 		   }
    641 
    642 		if (msg[1] == 'Y') {
    643 
    644 			/*
    645 			 * send file
    646 			 */
    647 			ASSERT(Role == MASTER, Wr_ROLE, "", Role);
    648 			if (fstat(fileno(fp), &stbuf)) /* never fail but .. */
    649 			    stbuf.st_size = 0;  /* for time loop calculation */
    650 
    651 			/*
    652 			 * If checkpoint restart is enabled, seek to the
    653 			 * starting point in the file.  We use hex because
    654 			 * C doesn't support unsigned long directly.
    655 			 */
    656 
    657 			if (Restart) {
    658 			    if((startp = strtol(&msg[2], (char **) 0, FLENRADIX))) {
    659 			        CDEBUG(1, "Restart point=0x%lx\n", startp);
    660 				if(startp < 0)
    661 				    sprintf(tbuf,"start=0x%lx", startp);
    662 				else
    663 				    sprintf(tbuf,"start=%ld", startp);
    664 				p = tbuf + strlen(tbuf);
    665 				if (stbuf.st_size < 0)
    666 				    sprintf(p,", length=0x%lx", stbuf.st_size);
    667 				else
    668 				    sprintf(p,", length=%ld", stbuf.st_size);
    669 
    670 				logent(tbuf, "RESTART");
    671 				errno = 0;
    672 				if (lseek(fileno(fp), startp, 0) == -1) {
    673 				    logent(strerror(errno), "FSEEK ERROR");
    674 				    (void) fclose(fp);
    675 				    (*Turnoff)();
    676 		    		    Seqn++;
    677 				    return(FAIL);
    678 				}
    679 				fp->_cnt = 0;
    680 				fp->_ptr = fp->_base;
    681 			    }
    682 			}
    683 			(void) millitick();	/* start msec timer */
    684 			pfStrtXfer(MCHAR, SNDFILE);
    685 			scStime(); 	/* log start transfer time for security log */
    686 
    687 		/* (ret != 0) implies the trammission error occurred.
    688      	           If checkpoint protocol is available then the next
    689 		   transfer will restart from the breakpoint of the file,
    690 		   otherwise from the beginning of the file  */
    691 
    692 			ret = (*Wrdata)(fp, Ofn);
    693 
    694 		/* the second millitick() returns the duration between
    695 		   the first and second call.
    696    		   writes "PARTIAL FILE to the transfer log indicating
    697 		   a transmission error. */
    698 
    699 			statlog( "->", getfilesize(), millitick(),
    700 					(ret) ? "PARTIAL FILE" : ""  );
    701 
    702 			acInc();	/* increment job size in accounting log					 */
    703 			pfEndXfer();
    704 			scEtime();	/* log end transfer time for security log */
    705 		    	Seqn++;
    706 			(void) fclose(fp);
    707 			if (ret != 0) {
    708 				pfEndfile("PARTIAL FILE");
    709 				acEnd(PARTIAL); /*stop collecting accounting log */
    710 				(*Turnoff)();
    711 				return(FAIL);
    712 			}
    713 
    714 			/* loop depending on the size of the file */
    715 			/* give an extra try for each megabyte */
    716 			for (im = stbuf.st_size >> 10; im >= 0; --im) {
    717 		    	    if ((ret = rmesg(RQSTCMPT, msg)) == 0)
    718 				break;	/* got message */
    719 			}
    720 			if (ret != 0) {
    721 			    (*Turnoff)();
    722 			     return(FAIL);
    723 			}
    724 			unlinkdf(W_DFILE);
    725 			goto process;
    726 		}
    727 
    728 		/*
    729 		 * SLAVE section of SNDFILE
    730 		 */
    731 		ASSERT(Role == SLAVE, Wr_ROLE, "", Role);
    732 
    733 		/*
    734 		 * request to receive file
    735 		 * check permissions
    736 		 */
    737 		i = getargs(msg, wrkvec, W_MAX);
    738 
    739 		scRequser(W_USER); /* log requestor user id */
    740 
    741 		/* log destination node, user and file name */
    742 
    743 		scDest(Myname,NOTAVAIL,W_FILE2);
    744 
    745 		/* log source node, file owner, file name, mod time and size */
    746 
    747 		scSrc(Rmtname,NOTAVAIL,W_FILE1,NOTAVAIL,NOTAVAIL);
    748 
    749 		/* Check for bad request */
    750 		if (i < W_MIN) {
    751 			WMESG(SNDFILE, EM_BADUUCP); /* you(remote master) gave me
    752 							bad work file */
    753 			logent("DENIED", "TOO FEW ARGS IN SLAVE SNDFILE");
    754 			goto top;
    755 		}
    756 		/* SLAVE gets the original filesize from sender (MASTER) */
    757 		/* This will be used to check the length of the P. file */
    758 		if (Restart) {
    759 		    if (W_FSIZE && (*W_FSIZE != '\0')) {
    760 			actualsize = strtol(W_FSIZE, (char **) 0, FLENRADIX);
    761 			CDEBUG(7, "Actual File Length %ld\n", actualsize);
    762 		    } else {
    763 			actualsize = -1;
    764 			CDEBUG(7, "Actual File Length Not Provided\n%s", "");
    765 		    }
    766 		}
    767 
    768 		mf = W_SFILE;
    769 		(void) sprintf(rqstr, "%s!%s --> %s!%s (%s)", Rmtname,
    770 			    W_FILE1, Myname, W_FILE2, W_USER);
    771 		logent(rqstr, "REMOTE REQUESTED");
    772 		DEBUG(4, "msg - %s\n", msg);
    773 		CDEBUG(1, "Remote Requested: %s\n", rqstr);
    774 		(void) strcpy(filename, W_FILE2);
    775 		expfile(filename);
    776 		DEBUG(4, "SLAVE - filename: %s\n", filename);
    777 		if (chkpth(filename, CK_WRITE)
    778 		     || chkperm(W_FILE1, filename, strchr(W_OPTNS, 'd'))) {
    779 			WMESG(SNDFILE, EM_RMTACC); /* you(remote master) can't
    780 						send data to this file(directory) */
    781 			logent("DENIED", "PERMISSION");
    782 			CDEBUG(1, "Failed: Access Denied\n%s", "");
    783 		    	scWrite(); /* log security violation */
    784 			goto top;
    785 		}
    786 		(void) sprintf(User, "%s", W_USER);
    787 
    788 		DEBUG(4, "chkpth ok Rmtname - %s\n", Rmtname);
    789 
    790 
    791 
    792 		if (Restart && (strlen(W_DFILE) > (size_t) 6)) {
    793 			if (noSpool()) {
    794 			    strcpy(Dfile, filename);	/* use Dest file directly */
    795 			    Pname(W_DFILE, Dfile, TRUE);
    796 			    if (! Restart)
    797 				unlink(Dfile);
    798 			}
    799 			else
    800 			    Pname(W_DFILE, Dfile, FALSE);
    801 		}
    802 		else {
    803 		    TMname(Dfile, pnum); /* get TM file name */
    804 		    unlink(Dfile);
    805 		}
    806 
    807 		/*
    808 		 * If the spool file exists, it better have the right owner
    809 		 * and permissions!
    810 		 */
    811 
    812 		if (Restart && noSpool()) {
    813 			if ((! stat(Dfile, &stbuf)) &&
    814 			    ((stbuf.st_mode != (DFILEMODE|S_IFREG)) ||
    815 			    ((stbuf.st_gid != UUCPGID) ||
    816 			     (stbuf.st_uid != UUCPUID)))) {
    817 			    WMESG(SNDFILE, EM_NOTMP); /* I(slave) see bad perms */
    818 			    logent("BAD DESTFILE OWNER/PERMS", "FAILED");
    819 			    CDEBUG(1, "Failed: bad dest file owner/perms 0%o\n", stbuf.st_mode);
    820 			    goto top;
    821 			}
    822 		}
    823 		if ( ((fp = fopen(Dfile, "a+")) == NULL) || nospace(Dfile) ) {
    824 			WMESG(SNDFILE, EM_NOTMP); /* I(slave) can't create TM file */
    825 			logent("CAN'T OPEN", "DENIED");
    826 			CDEBUG(1, "Failed: Can't Create Temp File\n%s", "");
    827 			unlinkdf(Dfile);
    828 			goto top;
    829 		}
    830 		chmod(Dfile, DFILEMODE);	/* no peeking! */
    831 		chown(Dfile, UUCPUID, UUCPGID);
    832 		if (Restart && (strlen(W_DFILE) > (size_t) 6)) {
    833 		    if(fstat(fileno(fp), &stbuf)) {
    834 			WMESG(SNDFILE, EM_NOTMP);
    835 			logent("CAN'T STAT", "DENIED");
    836 			CDEBUG(1, "Failed: Can't Stat Temp File\n%s", "");
    837 			unlinkdf(Dfile);
    838 			Seqn++;
    839 			goto top;
    840 		    }
    841 		    /*
    842 		     * find a good start point.  Take care of simple underflow
    843 		     * and the signed nature of longs.
    844 		     */
    845 
    846 		    DEBUG(7, "Dfile length 0x%lx\n", stbuf.st_size);
    847 		    startp = stbuf.st_size - (stbuf.st_size % BUFSIZ);
    848 		    if((stbuf.st_size >= 0) && (startp < 0))
    849 			startp = 0;
    850 
    851 		    if(startp)
    852 		    {
    853 			if(startp < 0)
    854 			    sprintf(tbuf,"start=0x%lx", startp);
    855 			else
    856 			    sprintf(tbuf,"start=%ld", startp);
    857 
    858 			logent(tbuf, "RESTART");
    859 		    }
    860 
    861 		    sprintf(tbuf, "%s 0x%lx", YES, startp);
    862 		    if (lseek(fileno(fp), startp, 0) == -1) {
    863 			WMESG(SNDFILE, EM_SEEK);
    864 			logent("CAN'T SEEK", "DENIED");
    865 			CDEBUG(1, "Failed, Can't seek in Dfile\n%s", "");
    866 			unlinkdf(Dfile);
    867 			Seqn++;
    868 			goto top;
    869 		    }
    870 		    fp->_cnt = 0;
    871 		    fp->_ptr = fp->_base;
    872 		    CDEBUG(1," restart msg %s\n", tbuf);
    873 		    WMESG(SNDFILE, tbuf);
    874 		}
    875 		else
    876 		    WMESG(SNDFILE, YES);	/* I(slave) clear to send */
    877 		(void) millitick();	/* start msec timer */
    878 		pfStrtXfer(SCHAR, RCVFILE);
    879 		scStime(); 	/* log start transfer time for security log */
    880 		/* (ret != 0) implies the trammission error occurred.
    881      	           If checkpoint protocol is available then the next
    882 		   recieve will restart from the breakpoint of the file,
    883 		   otherwise from the beginning of the file  */
    884 
    885 		setline(RCVFILE);
    886 		ret = (*Rddata)(Ifn, fp);
    887 		setline(SNDFILE);
    888 
    889 		/* the second millitick() returns the duration between
    890 		   the first and second call.
    891    		   writes "PARTIAL FILE to the transfer log indicating
    892 		   a transmission error. */
    893 
    894 		statlog( "<-", getfilesize(), millitick(),
    895 				(ret) ? "PARTIAL FILE" : ""  );
    896 
    897 		pfEndXfer();
    898 		scEtime();	/* log end transfer time for security log */
    899 		Seqn++;
    900 
    901 		if (ret != 0) {
    902 			pfEndfile("PARTIAL FILE");
    903 			(void) fclose(fp);
    904 			if ( ret == EFBIG ) {
    905 				WMESG(RQSTCMPT, EM_ULIMIT);
    906 				logent("FILE EXCEEDS ULIMIT","FAILED");
    907 				CDEBUG(1, "Failed: file size exceeds ulimit%s\n", "");
    908 				goto top;
    909 			}
    910 			(*Turnoff)();
    911 			logent("INPUT FAILURE", "IN SEND/SLAVE MODE");
    912 			return(FAIL);
    913 		}
    914 		if (Restart && (actualsize != -1)) {
    915 		    if (fstat(fileno(fp), &stbuf)) {
    916 			(void) fclose(fp);
    917 			unlinkdf(Dfile);
    918 			(*Turnoff)();
    919 			logent("CAN'T STAT PFILE", "FAILED");
    920 			return(FAIL);
    921 		    }
    922 		    if (stbuf.st_size != actualsize) {
    923 			(void) fclose(fp);
    924 			unlinkdf(Dfile);
    925 			(*Turnoff)();
    926 			logent("RECEIVED SIZE NOT EQUAL TO ACTUAL SIZE", "FAILED");
    927 			CDEBUG(1, "Failed: receive size %ld ", stbuf.st_size);
    928 			CDEBUG(1, "not equal to actual size %ld\n", actualsize);
    929 			return(FAIL);
    930 		    }
    931 		}
    932 		(void) fclose(fp);
    933 
    934 		/* copy to user directory */
    935 		ntfyopt = strchr(W_OPTNS, 'n') != NULL;
    936 
    937 		/*
    938 		 * See if spool file and target file in the same file system
    939 		 */
    940 
    941 		ret = 0;
    942 		if (p = strrchr(Dfile, '/'))
    943 		{
    944 			*p = '\0';
    945 			ret = PREFIX(Dfile, filename);
    946 			*p = '/';
    947 		}
    948 
    949 		if (noSpool() && ret)
    950 		{
    951 		    /*
    952 		     * if we are not already in the right file, and
    953 		     * it is theoretically in the same file system,
    954 		     * link it there...
    955 		     */
    956 
    957 		    if(strcmp (filename, Dfile)) {
    958 			    unlink(filename);
    959 			    if(link(Dfile, filename))
    960 			    {
    961 				logent("FAILED", "MOVE");
    962 				scWrite();
    963 				putinpub(filename, Dfile, BASENAME(W_USER,'!'));
    964 			    }
    965 			    else
    966 	    			DEBUG(7, "linked Point file to %s\n", filename);
    967 			    unlink(Dfile);
    968 		    }
    969 		    else
    970 		    	DEBUG(7, "Point file and %s the same\n", filename);
    971 		    status = 0;			/* all done */
    972 		}
    973 		else
    974 		    status = xmv(Dfile, filename);
    975 
    976 		scSize(Dfile);	/* log source file size */
    977 		WMESG(RQSTCMPT, status ? EM_RMTCP : YES);
    978 		if (status == 0) {
    979 			sscanf(W_MODE, "%lo", &lfilemode);
    980 			if (lfilemode <= 0)
    981 				filemode = PUB_FILEMODE;
    982 			else
    983 				filemode = (mode_t)lfilemode;
    984 			if (PREFIX(RemSpool, filename))
    985 			    chmod(filename, DFILEMODE);
    986 			else
    987 			    chmod(filename, (filemode & LEGALMODE) | PUB_FILEMODE);
    988 			arrived(ntfyopt, filename, W_NUSER, Rmtname, User);
    989 		} else {
    990 			logent("FAILED",  "COPY");
    991 			scWrite();	/* log the security violation */
    992 			status = putinpub(filename, Dfile,
    993 			    BASENAME(W_USER, '!'));
    994 			DEBUG(4, "->PUBDIR %d\n", status);
    995 			if (status == 0)
    996 				arrived(ntfyopt, filename, W_NUSER,
    997 				    Rmtname, User);
    998 		}
    999 		pfEndfile("");	/* "" indicates the file transfer completely */
   1000 		if ( W_FILE2[1] == '.'  &&
   1001 		    (W_FILE2[0] == XQTPRE || W_FILE2[0] == DATAPRE) )
   1002 			uuxqtflag = 1;
   1003 		goto top;
   1004 
   1005 	case RCVFILE:
   1006 
   1007 		/*
   1008 		 * MASTER section of RCVFULE
   1009 		 */
   1010 		DEBUG(4, "%s\n", "RCVFILE:");
   1011 		if (msg[1] == 'N') {
   1012 			i = atoi(&msg[2]);
   1013 			if (i < 0 || i > EM_MAX)
   1014 				i = 0;
   1015 			logent(Em_msg[i], "REQUEST");
   1016 		        notify(mailopt, W_USER, rqstr, Rmtname, &msg[1]);
   1017 			ASSERT(Role == MASTER, Wr_ROLE, "", Role);
   1018 			(void) fclose(fp);
   1019 			unlinkdf(Dfile);
   1020 		    	scWrite();	/* something is wrong on other side,
   1021 					   log the security violation */
   1022 			goto top;
   1023 		}
   1024 
   1025 		if (msg[1] == 'Y') {
   1026 
   1027 		/* MASTER gets the original filesize from sender (SLAVE) */
   1028 		/* This will be used to check the length of the P. file */
   1029 			if (Restart) {
   1030 			    *fsize = '\0';
   1031 			    sscanf(&msg[2], "%*o %s", fsize);
   1032