xref: /illumos-gate/usr/src/cmd/bnu/cntrl.c (revision c3232c9513a02e659ae9307db0fc93d9730704f6)
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 #include "uucp.h"
32 #include "log.h"
33 
34 void notify(), lnotify(), unlinkdf(), arrived();
35 static void stmesg();
36 static int nospace();
37 
38 struct Proto {
39 	char P_id;
40 	int (*P_turnon)();
41 	int (*P_rdmsg)();
42 	int (*P_wrmsg)();
43 	int (*P_rddata)();
44 	int (*P_wrdata)();
45 	int (*P_turnoff)();
46 };
47 
48 extern char _Protocol[];
49 extern char *findProto();
50 
51 extern char uuxqtarg[];
52 
53 extern int gturnon(), gturnoff();
54 extern int grdmsg(), grddata();
55 extern int gwrmsg(), gwrdata();
56 
57 extern int wmesg(), rmesg(), expfile(), putinpub(), stptcl();
58 extern void setline(), TMname(), cleanup(), pfEndfile(), statlog(), mailst();
59 
60 #ifdef	D_PROTOCOL
61 extern int dturnon(), dturnoff();
62 extern int drdmsg(), drddata();
63 extern int dwrmsg(), dwrdata();
64 #endif	/* D_PROTOCOL */
65 
66 #ifdef	X_PROTOCOL
67 extern int xturnon(), xturnoff();
68 extern int xrdmsg(), xrddata();
69 extern int xwrmsg(), xwrdata();
70 #endif	/* X_PROTOCOL */
71 
72 #ifdef E_PROTOCOL
73 extern int eturnon(), eturnoff();
74 extern int erdmsg(), erddata();
75 extern int ewrmsg(), ewrdata();
76 extern int trdmsg(), twrmsg();
77 extern int trddata(), twrdata();
78 #endif /* E_PROTOCOL */
79 
80 #ifdef F_PROTOCOL
81 extern int fturnon(), fturnoff();
82 extern int frdmsg(), frddata();
83 extern int fwrmsg(), fwrdata();
84 #endif	/* F_PROTOCOL */
85 
86 extern int imsg();
87 extern int omsg();
88 extern int turnoff();
89 extern long strtol();
90 
91 struct Proto Ptbl[]={
92 	{'g', gturnon, grdmsg, gwrmsg, grddata, gwrdata, gturnoff},
93 	{'G', gturnon, grdmsg, gwrmsg, grddata, gwrdata, gturnoff},
94 
95 #ifdef E_PROTOCOL
96 	{'e', eturnon, erdmsg, ewrmsg, erddata, ewrdata, eturnoff},
97 	{'t', eturnon, trdmsg, twrmsg, trddata, twrdata, eturnoff},
98 #endif /* E_PROTOCOL */
99 
100 #ifdef	D_PROTOCOL
101 	{'d', dturnon, drdmsg, dwrmsg, drddata, dwrdata, dturnoff},
102 #endif	/* D_PROTOCOL */
103 
104 #ifdef	X_PROTOCOL
105 	{'x', xturnon, xrdmsg, xwrmsg, xrddata, xwrdata, xturnoff},
106 #endif	/* X_PROTOCOL */
107 
108 #ifdef	F_PROTOCOL
109 	{'f', fturnon, frdmsg, fwrmsg, frddata, fwrdata, fturnoff},
110 #endif	/* F_PROTOCOL */
111 	'\0'
112 };
113 
114 #define VALIDSIZE sizeof(Ptbl)/sizeof(struct Proto)
115 
116 int (*Rdmsg)()=imsg, (*Rddata)();
117 int (*Wrmsg)()=omsg, (*Wrdata)();
118 int (*Turnon)(), (*Turnoff)()=turnoff;
119 
120 
121 #define YES "Y"
122 #define NO "N"
123 
124 #define TBUFSIZE	128	/* temporary buffer size */
125 #define FLENRADIX	(16)	/* output radix for file start point */
126 
127 /*
128  * failure messages
129  */
130 #define EM_MAX		10
131 #define EM_LOCACC	"N1"	/* local access to file denied */
132 #define EM_RMTACC	"N2"	/* remote access to file/path denied */
133 #define EM_BADUUCP	"N3"	/* a bad uucp command was generated */
134 #define EM_NOTMP	"N4"	/* remote error - can't create temp */
135 #define EM_RMTCP	"N5"	/* can't copy to remote directory - file in public */
136 #define EM_LOCCP	"N6"	/* can't copy on local system */
137 #define EM_SEEK		"N7"	/* can't seek to checkpoint */
138 /* 	EM_		"N8" */	/* placeholder*/
139 /* 	EM_		"N9" */	/* placeholder*/
140 #define EM_ULIMIT	"N10"	/* receiver ulimit exceeded */
141 
142 char *Em_msg[] = {
143 	"COPY FAILED (reason not given by remote)",
144 	"local access to file denied",
145 	"remote access to path/file denied",
146 	"system error - bad uucp command generated",
147 	"remote system can't create temp file",
148 	"can't copy to file/directory - file left in PUBDIR/user/file",
149 	"can't copy to file/directory - file left in PUBDIR/user/file",
150 	"can't seek to checkpoint",
151 	"COPY FAILED (reason not given by remote)", /* placeholder */
152 	"COPY FAILED (reason not given by remote)", /* placeholder */
153 	"file exceeds ulimit of receiving system",
154 	"forwarding error"
155 };
156 
157 
158 #define XUUCP 'X'	/* execute uucp (string) */
159 #define SLTPTCL 'P'	/* select protocol  (string)  */
160 #define USEPTCL 'U'	/* use protocol (character) */
161 #define RCVFILE 'R'	/* receive file (string) */
162 #define SNDFILE 'S'	/* send file (string) */
163 #define RQSTCMPT 'C'	/* request complete (string - yes | no) */
164 #define HUP     'H'	/* ready to hangup (string - yes | no) */
165 #define RESET	'X'	/* reset line modes */
166 
167 #define W_MAX		10	/* maximum number of C. files per line */
168 #define W_MIN		7	/* min number of entries */
169 #define W_TYPE		wrkvec[0]
170 #define W_FILE1		wrkvec[1]
171 #define W_FILE2		wrkvec[2]
172 #define W_USER		wrkvec[3]
173 #define W_OPTNS		wrkvec[4]
174 #define W_DFILE		wrkvec[5]
175 #define W_MODE		wrkvec[6]
176 #define W_NUSER		wrkvec[7]
177 #define W_SFILE		wrkvec[8]
178 #define W_RDFILE	wrkvec[8]
179 #define W_POINT		wrkvec[9]
180 #define W_FSIZE		wrkvec[9]
181 #define W_RFILE		wrkvec[5]
182 #define W_XFILE		wrkvec[5]
183 char	*mf;
184 
185 #define RMESG(m, s) if (rmesg(m, s) != 0) {(*Turnoff)(); return(FAIL);}
186 #define RAMESG(s) if (rmesg('\0', s) != 0) {(*Turnoff)(); return(FAIL);}
187 #define WMESG(m, s) if(wmesg(m, s) != 0) {(*Turnoff)(); return(FAIL);}
188 
189 char Wfile[MAXFULLNAME] = {'\0'};
190 char Dfile[MAXFULLNAME];
191 
192 char	*wrkvec[W_MAX+1];
193 int	statfopt;
194 
195 /*
196  * Create restart point filename
197  */
198 
199 static void
200 Pname(fileid, dfile, direct)
201   char *fileid;
202   char *dfile;
203   int  direct;		/* indicates a direct delivery temp file nameneeded */
204 {
205     char *p;
206 
207 	    /*
208 	     * If the file is direct delivery, then its name is:
209 	     *
210 	     *		/dir/dir/dir/.Pnnnnnnnn
211 	     *
212 	     * in the target directory.  We create this by replacing the
213 	     * name of the target file with the D.nnnnnn name from the
214 	     * work vector, and then overwriting the D. with .P
215 	     */
216 
217 	    if (direct) {
218 		if (p = strrchr(dfile, '/')) {	/* find the last slash */
219 			p++;
220 			strcpy(p, fileid);	/* append D.nnnnn name to dir */
221 			*p++ = '.';
222 			*p = 'P';		/* replace beginning with .P */
223 	    		DEBUG(7, "Point file (direct) =%s\n", dfile);
224 			return;
225 		}
226 	    }
227 	    strcpy(dfile, RemSpool);
228 	    strcat(dfile, "/");
229 	    p = dfile + strlen(Dfile);
230 	    strcat(dfile, fileid);
231 	    *p = 'P';
232 	    DEBUG(7, "Point file=%s\n", dfile);
233 	return;
234 }
235 
236 
237 /*
238  * execute the conversation between the two machines
239  * after both programs are running.
240  * returns:
241  *	SUCCESS 	-> ok
242  *	FAIL 		-> failed
243  */
244 int
245 cntrl()
246 {
247 	FILE * fp;
248 	struct stat stbuf;
249 	char *	p;
250 	long 	startp;		/* checkpoint restart point */
251 	long	actualsize;	/* actual file size */
252 	long	im;
253 	long	lfilemode;
254 	mode_t	filemode;
255 	int	status;
256 	int	i, narg;
257 	int	mailopt, ntfyopt;
258 	int	ret;
259 	char	tbuf[TBUFSIZE];
260 	char	rqstr[BUFSIZ];	/* contains the current request message */
261 	char	msg[BUFSIZ];
262 	char	filename[MAXFULLNAME], wrktype;
263 	char	fsize[NAMESIZE];	/* holds file size/checkpoint string */
264 	char	localname[MAXFULLNAME];	/* real local system name */
265 	char	Recspool[MAXFULLNAME];	/* spool area for slave uucico */
266 	static pid_t	pnum;
267 	extern int uuxqtflag;	/* set if received X. or D. file */
268 
269 	pnum = getpid();
270 	Wfile[0] = '\0';
271 	(void) sprintf(Recspool, "%s/%s", SPOOL, Rmtname);
272 top:
273 	(void) strcpy(User, Uucp);
274 	statfopt = 0;
275 	*Jobid = '\0';
276 	DEBUG(4, "*** TOP ***  -  Role=%d, ", Role);
277 	setline(RESET);
278 	if (Role == MASTER) {
279 
280 		/*
281 		 * get work
282 		 */
283 		pfFindFile();
284 		if ((narg = gtwvec(Wfile, wrkvec, W_MAX)) == 0) {
285 			acEnd(COMPLETE); /*stop collecting accounting log */
286 			WMESG(HUP, ""); /* I(master) am done. want me to quit? */
287 			RMESG(HUP, msg);
288 			goto process;
289 		}
290 		DEBUG(7, "Wfile - %s,", Wfile);
291 		strncpy(Jobid, BASENAME(Wfile, '/')+2, NAMESIZE);
292 		Jobid[NAMESIZE-1] = '\0';
293 		DEBUG(7, "Jobid = %s\n", Jobid);
294 		wrktype = W_TYPE[0];
295 		pfFound(Jobid, W_OPTNS, Nstat.t_qtime);
296 		mailopt = strchr(W_OPTNS, 'm') != NULL;
297 		statfopt = strchr(W_OPTNS, 'o') != NULL;
298 		ntfyopt = strchr(W_OPTNS, 'n') != NULL;
299 
300 		uucpname(localname); /* get real local machine name */
301 		acDojob(Jobid, localname, W_USER);
302 		scRequser(W_USER); /* log requestor user id */
303 
304 		/*
305 		 * We used to check for corrupt workfiles here (narg < 5),
306 		 * but we were doing it wrong, and besides, anlwrk.c is the
307 		 * appropriate place to do it.
308 		 */
309 
310 		(void) sprintf(User, "%s", W_USER);
311 		if (wrktype == SNDFILE ) {
312 			(void) sprintf(rqstr, "%s!%s --> %s!%s (%s)", Myname,
313 			    W_FILE1, Rmtname, W_FILE2, User);
314 
315 			/* log destination node, user and file name */
316 
317 			scDest(Rmtname,NOTAVAIL,W_FILE2);
318 
319 			/* log source node, file owner, file name, mod time and size */
320 
321 			scSrc(Myname,scOwn(W_FILE1),W_FILE1,scMtime(W_FILE1)
322 						,scSize(W_FILE1));
323 
324 			logent(rqstr, "REQUEST");
325 			CDEBUG(1, "Request: %s\n", rqstr);
326 			mf = W_SFILE;
327 			(void) strcpy(filename, W_FILE1);
328 			expfile(filename);
329 			(void) strcpy(Dfile, W_DFILE);
330 			if ( (fp = fopen(Dfile, "r")) == NULL) {
331 			    if ( (fp = fopen(filename, "r")) == NULL) {
332 				/*  cannot read spool or original file */
333 				unlinkdf(Dfile);
334 				lnotify(User, rqstr, "can't access");
335 				(void) sprintf(msg, "CAN'T READ %s %d",
336 					filename, errno);
337 				logent(msg, "FAILED");
338 				CDEBUG(1, "Failed: Can't Read %s\n", filename);
339 		    		scWrite();	/* log the security violation */
340 				goto top;
341 			    } else {
342 				/* ensure original file is publicly readable */
343 				if ( !F_READANY(fileno(fp)) ) {
344 				    /* access denied */
345 				    logent("DENIED", "ACCESS");
346 				    unlinkdf(W_DFILE);
347 				    lnotify(User, rqstr, "access denied");
348 				    CDEBUG(1, "Failed: Access Denied\n%s", "");
349 		    		    scWrite();	/* log the security violation */
350 				    goto top;
351 				}
352 			    }
353 			}
354 
355 			if (Restart && !(fstat(fileno(fp), &stbuf))) {
356 				(void) sprintf(fsize, "0x%lx", stbuf.st_size);
357 				W_FSIZE = fsize; /* set file size in vector */
358 			}
359 
360 			/* Check whether remote's ulimit is exceeded */
361 			if (SizeCheck) {
362 				if (((stbuf.st_size-1)/512 + 1) > RemUlimit) {
363 					/* remote ulimit exceeded */
364 					unlinkdf(Dfile);
365 					lnotify(User, rqstr, "remote ulimit exceeded");
366 					logent("DENIED", "REMOTE ULIMIT EXCEEDED");
367 					CDEBUG(1, "Denied: remote ulimit exceeded %s\n", filename);
368 					scWrite();
369 					(void) fclose(fp);
370 					goto top;
371 				}
372 			}
373 		}
374 
375 		if (wrktype == RCVFILE) {
376 			(void) sprintf(rqstr, "%s!%s --> %s!%s (%s)", Rmtname,
377 			    W_FILE1, Myname, W_FILE2, User);
378 
379 			/* log destination node, user and file name */
380 
381 			scDest(Myname,NOTAVAIL,W_FILE2);
382 
383 			/* log source node, file owner, file name, mod time and size */
384 
385 			scSrc(Rmtname,NOTAVAIL,W_FILE1,NOTAVAIL,NOTAVAIL);
386 
387 			logent(rqstr, "REQUEST");
388 			CDEBUG(1, "Request: %s\n", rqstr);
389 			mf = W_RFILE;
390 			(void) strcpy(filename, W_FILE2);
391 
392 			/* change Wrkdir to SPOOL/Rmtname in case the file being
393 			** requested is needed for some remote execution.
394 			*/
395 
396 			(void) strcpy(Wrkdir, Recspool);
397 			expfile(filename);
398 
399 			/* now change Wrkdir back to what it was
400 			** just being paranoid.
401 			*/
402 
403 			(void) strcpy(Wrkdir, RemSpool);
404 			if (chkperm(W_FILE1, filename, strchr(W_OPTNS, 'd'))) {
405 
406 				/* access denied */
407 				logent("DENIED", "ACCESS");
408 				lnotify(User, rqstr, "access denied");
409 				CDEBUG(1, "Failed: Access Denied--File: %s\n",
410 				    filename);
411 		    		scWrite();	/* log the security violation */
412 				goto top;
413 			}
414 
415 			/*
416 			 * If we are not going to spool the file in the spool
417 			 * directory, just use the destination file name.  If we
418 			 * are not supporting restart, wipe out the target file.
419 			 * else:
420 			 *
421 			 * If restart is enabled, make up the Point file name
422 			 * as the file to open, else use the TM style name.
423 			 *
424 			 * If we run into a spool name of "D.0", this implies
425 			 * that someone forgot to install the new uucp and
426 			 * uux commands.  Such jobs will not be checkpointed.
427 			 */
428 
429 
430 			if (Restart && (strlen(W_RDFILE) > (size_t) 6)) {
431 				if (noSpool()) {
432 				    strcpy(Dfile, filename);	/* use Dest file directly */
433 				    Pname(W_RDFILE, Dfile, TRUE);
434 				}
435 				else
436 				    Pname(W_RDFILE, Dfile, FALSE);
437 			}
438 			else {
439 			    TMname(Dfile, pnum); /* get TM file name */
440 			    unlink(Dfile);
441 			}
442 
443 			/*
444 			 * If the spool file exists, it better have the right owner
445 			 * and permissions!
446 			 */
447 
448 			if (Restart && noSpool()) {
449 				if ((! stat(Dfile, &stbuf)) &&
450 				    ((stbuf.st_mode != (DFILEMODE|S_IFREG)) ||
451 				    ((stbuf.st_gid != UUCPGID) ||
452 				     (stbuf.st_uid != UUCPUID)))) {
453 				    lnotify(User, rqstr,
454 					"bad spool file ownership/permissions");
455 				    logent("BAD DESTFILE OWNER/PERMS", "FAIL");
456 				    CDEBUG(1, "Failed: bad dest file owner/perms 0%o; fail\n", stbuf.st_mode);
457 				    goto top;
458 				}
459 			}
460 			if ( ((fp = fopen(Dfile, "a+")) == NULL)
461 			     || nospace(Dfile)) {
462 
463 				/* can not create temp */
464 				if (noSpool())
465 				    logent("CAN'T CREATE/OPEN DEST FILE", "FAILED");
466 				else
467 				    logent("CAN'T CREATE TM FILE", "FAILED");
468 				CDEBUG(1, "Failed: No Space!\n%s", "");
469 				unlinkdf(Dfile);
470 				assert(Ct_CREATE, Dfile, nospace(Dfile),
471 				    __FILE__, __LINE__);
472 				cleanup(FAIL);
473 			}
474 
475 			/*
476 			 * Send the W_POINT value to the other side.
477 			 */
478 
479 			if (Restart) {
480 			    if (fstat (fileno(fp), &stbuf)) {
481 				logent("CAN'T STAT DFILE", "START FROM BEGINNING");
482 				stbuf.st_size = 0L;
483 			    }
484 
485 			    /*
486 			     * find a good start point.  Take care of simple
487 			     * underflow and the signed nature of longs.
488 			     */
489 
490 			    DEBUG(7, "Dfile length 0x%lx\n", stbuf.st_size);
491 			    startp = stbuf.st_size - (stbuf.st_size % BUFSIZ);
492 			    if((stbuf.st_size >= 0) && (startp < 0))
493 				startp = 0;
494 
495 			    if(startp)
496 			    {
497 				if(startp < 0)
498 				    sprintf(tbuf,"start=0x%lx", startp);
499 				else
500 				    sprintf(tbuf,"start=%ld", startp);
501 
502 				logent(tbuf, "RESTART");
503 			    }
504 
505 			    sprintf(fsize, "0x%lx", startp);
506 			    W_POINT = fsize; /* set start point in vector */
507 			    if (lseek(fileno(fp), startp, 0) == -1) {
508 				WMESG(SNDFILE, EM_SEEK);
509 				logent("CAN'T SEEK", "DENIED");
510 				CDEBUG(1, "Failed, Can't seek in Dfile\n%s", "");
511 				unlinkdf(Dfile);
512 				goto top;
513 		    	    }
514 		    	    fp->_cnt = 0;
515 		    	    fp->_ptr = fp->_base;
516 			}
517 
518 			Seqn++;
519 			chmod(Dfile, DFILEMODE);	/* no peeking! */
520 			chown(Dfile, UUCPUID, UUCPGID);
521 
522 		}
523 		DEBUG(4, "wrktype - %c\n ", wrktype);
524 
525 		/* Build up the message itself */
526 
527 		msg[0] = '\0';
528 		for (i = 1; i < narg; i++) {
529 			(void) strcat(msg, " ");
530 			(void) strcat(msg, wrkvec[i]);
531 		}
532 
533 		WMESG(wrktype, msg); /* I(master) am sending you our work file */
534 		RMESG(wrktype, msg); /* I(master) am waiting for your response */
535 		goto process;
536 	}
537 
538 	/*
539 	 * role is slave
540 	 */
541 
542 	RAMESG(msg); /* I(slave) am waiting for our work file */
543 
544 process:
545 
546 	DEBUG(4, " PROCESS: msg - %s\n", msg);
547 	switch (msg[0]) {
548 
549 	case RQSTCMPT:
550 		DEBUG(4, "%s\n", "RQSTCMPT:");
551 		if (msg[1] == 'N') {
552 			i = atoi(&msg[2]);
553 			if (i < 0 || i > EM_MAX)
554 				i = 0;
555 			logent(Em_msg[i], "REQUESTED");
556 		}
557 		if (Role == MASTER) {
558 		        notify(mailopt, W_USER, rqstr, Rmtname, &msg[1]);
559 		}
560 		pfEndfile("");	/* "" indicates the file transfer completely */
561 		goto top;
562 
563 	case HUP:
564 		DEBUG(4, "%s\n", "HUP:");
565 		if (msg[1] == 'Y') {
566 			WMESG(HUP, YES); /* let's quit */
567 			(*Turnoff)();
568 			Rdmsg = imsg;
569 			Wrmsg = omsg;
570 			Turnoff = turnoff;
571 			return(0);
572 		}
573 
574 		if (msg[1] == 'N') {
575 			ASSERT(Role == MASTER, Wr_ROLE, "", Role);
576 			Role = SLAVE;
577 			scReqsys(Rmtname); /* log requestor system */
578 			chremdir(Rmtname);
579 			goto top;
580 		}
581 
582 		/*
583 		 * get work
584 		 */
585 		if ( (switchRole() == FALSE) || !iswrk(Wfile) ) {
586 			DEBUG(5, "SLAVE-switchRole (%s)\n",
587 			    switchRole() ? "TRUE" : "FALSE");
588 			WMESG(HUP, YES); /* let's quit */
589 			RMESG(HUP, msg);
590 			goto process;
591 		}
592 
593 		/* Note that Wfile is the first C. to process at top
594 		 * set above by iswrk() call
595 		 */
596 		if (uuxqtflag) {
597 			xuuxqt(uuxqtarg);
598 			uuxqtflag = 0;
599 		}
600 		WMESG(HUP, NO); /* don't quit. I(slave) have more to do */
601 		Role = MASTER;
602 		uucpname(localname); /* get real local machine name */
603 		scReqsys(localname); /* log requestor system */
604 		acInit("xfer");
605 		goto top;
606 
607 	case XUUCP:
608 		/*
609 		 * slave part
610 		 * No longer accepted
611 		 */
612 
613 		WMESG(XUUCP, NO);
614 		goto top;
615 
616 	case SNDFILE:
617 
618 		/*
619 		 * MASTER section of SNDFILE
620 		 */
621 		DEBUG(4, "%s\n", "SNDFILE:");
622 		if (msg[1] == 'N')
623 		   {
624 		    i = atoi(&msg[2]);
625 		    if (i < 0 || i > EM_MAX)
626 			i = 0;
627 		    logent(Em_msg[i], "REQUEST");
628 		    notify(mailopt, W_USER, rqstr, Rmtname, &msg[1]);
629 		    ASSERT(Role == MASTER, Wr_ROLE, "", Role);
630 		    (void) fclose(fp);
631 		    /* if remote is out of tmp space, then just hang up */
632 		    ASSERT(i != 4, Em_msg[4], Rmtname, i);	/* EM_NOTMP */
633 		    unlinkdf(W_DFILE);
634 		    scWrite();	/* something is wrong on other side,
635 				   log the security violation */
636 		    Seqn++;
637 		    goto top;
638 		   }
639 
640 		if (msg[1] == 'Y') {
641 
642 			/*
643 			 * send file
644 			 */
645 			ASSERT(Role == MASTER, Wr_ROLE, "", Role);
646 			if (fstat(fileno(fp), &stbuf)) /* never fail but .. */
647 			    stbuf.st_size = 0;  /* for time loop calculation */
648 
649 			/*
650 			 * If checkpoint restart is enabled, seek to the
651 			 * starting point in the file.  We use hex because
652 			 * C doesn't support unsigned long directly.
653 			 */
654 
655 			if (Restart) {
656 			    if((startp = strtol(&msg[2], (char **) 0, FLENRADIX))) {
657 			        CDEBUG(1, "Restart point=0x%lx\n", startp);
658 				if(startp < 0)
659 				    sprintf(tbuf,"start=0x%lx", startp);
660 				else
661 				    sprintf(tbuf,"start=%ld", startp);
662 				p = tbuf + strlen(tbuf);
663 				if (stbuf.st_size < 0)
664 				    sprintf(p,", length=0x%lx", stbuf.st_size);
665 				else
666 				    sprintf(p,", length=%ld", stbuf.st_size);
667 
668 				logent(tbuf, "RESTART");
669 				errno = 0;
670 				if (lseek(fileno(fp), startp, 0) == -1) {
671 				    logent(strerror(errno), "FSEEK ERROR");
672 				    (void) fclose(fp);
673 				    (*Turnoff)();
674 		    		    Seqn++;
675 				    return(FAIL);
676 				}
677 				fp->_cnt = 0;
678 				fp->_ptr = fp->_base;
679 			    }
680 			}
681 			(void) millitick();	/* start msec timer */
682 			pfStrtXfer(MCHAR, SNDFILE);
683 			scStime(); 	/* log start transfer time for security log */
684 
685 		/* (ret != 0) implies the trammission error occurred.
686      	           If checkpoint protocol is available then the next
687 		   transfer will restart from the breakpoint of the file,
688 		   otherwise from the beginning of the file  */
689 
690 			ret = (*Wrdata)(fp, Ofn);
691 
692 		/* the second millitick() returns the duration between
693 		   the first and second call.
694    		   writes "PARTIAL FILE to the transfer log indicating
695 		   a transmission error. */
696 
697 			statlog( "->", getfilesize(), millitick(),
698 					(ret) ? "PARTIAL FILE" : ""  );
699 
700 			acInc();	/* increment job size in accounting log					 */
701 			pfEndXfer();
702 			scEtime();	/* log end transfer time for security log */
703 		    	Seqn++;
704 			(void) fclose(fp);
705 			if (ret != 0) {
706 				pfEndfile("PARTIAL FILE");
707 				acEnd(PARTIAL); /*stop collecting accounting log */
708 				(*Turnoff)();
709 				return(FAIL);
710 			}
711 
712 			/* loop depending on the size of the file */
713 			/* give an extra try for each megabyte */
714 			for (im = stbuf.st_size >> 10; im >= 0; --im) {
715 		    	    if ((ret = rmesg(RQSTCMPT, msg)) == 0)
716 				break;	/* got message */
717 			}
718 			if (ret != 0) {
719 			    (*Turnoff)();
720 			     return(FAIL);
721 			}
722 			unlinkdf(W_DFILE);
723 			goto process;
724 		}
725 
726 		/*
727 		 * SLAVE section of SNDFILE
728 		 */
729 		ASSERT(Role == SLAVE, Wr_ROLE, "", Role);
730 
731 		/*
732 		 * request to receive file
733 		 * check permissions
734 		 */
735 		i = getargs(msg, wrkvec, W_MAX);
736 
737 		scRequser(W_USER); /* log requestor user id */
738 
739 		/* log destination node, user and file name */
740 
741 		scDest(Myname,NOTAVAIL,W_FILE2);
742 
743 		/* log source node, file owner, file name, mod time and size */
744 
745 		scSrc(Rmtname,NOTAVAIL,W_FILE1,NOTAVAIL,NOTAVAIL);
746 
747 		/* Check for bad request */
748 		if (i < W_MIN) {
749 			WMESG(SNDFILE, EM_BADUUCP); /* you(remote master) gave me
750 							bad work file */
751 			logent("DENIED", "TOO FEW ARGS IN SLAVE SNDFILE");
752 			goto top;
753 		}
754 		/* SLAVE gets the original filesize from sender (MASTER) */
755 		/* This will be used to check the length of the P. file */
756 		if (Restart) {
757 		    if (W_FSIZE && (*W_FSIZE != '\0')) {
758 			actualsize = strtol(W_FSIZE, (char **) 0, FLENRADIX);
759 			CDEBUG(7, "Actual File Length %ld\n", actualsize);
760 		    } else {
761 			actualsize = -1;
762 			CDEBUG(7, "Actual File Length Not Provided\n%s", "");
763 		    }
764 		}
765 
766 		mf = W_SFILE;
767 		(void) sprintf(rqstr, "%s!%s --> %s!%s (%s)", Rmtname,
768 			    W_FILE1, Myname, W_FILE2, W_USER);
769 		logent(rqstr, "REMOTE REQUESTED");
770 		DEBUG(4, "msg - %s\n", msg);
771 		CDEBUG(1, "Remote Requested: %s\n", rqstr);
772 		(void) strcpy(filename, W_FILE2);
773 		expfile(filename);
774 		DEBUG(4, "SLAVE - filename: %s\n", filename);
775 		if (chkpth(filename, CK_WRITE)
776 		     || chkperm(W_FILE1, filename, strchr(W_OPTNS, 'd'))) {
777 			WMESG(SNDFILE, EM_RMTACC); /* you(remote master) can't
778 						send data to this file(directory) */
779 			logent("DENIED", "PERMISSION");
780 			CDEBUG(1, "Failed: Access Denied\n%s", "");
781 		    	scWrite(); /* log security violation */
782 			goto top;
783 		}
784 		(void) sprintf(User, "%s", W_USER);
785 
786 		DEBUG(4, "chkpth ok Rmtname - %s\n", Rmtname);
787 
788 
789 
790 		if (Restart && (strlen(W_DFILE) > (size_t) 6)) {
791 			if (noSpool()) {
792 			    strcpy(Dfile, filename);	/* use Dest file directly */
793 			    Pname(W_DFILE, Dfile, TRUE);
794 			    if (! Restart)
795 				unlink(Dfile);
796 			}
797 			else
798 			    Pname(W_DFILE, Dfile, FALSE);
799 		}
800 		else {
801 		    TMname(Dfile, pnum); /* get TM file name */
802 		    unlink(Dfile);
803 		}
804 
805 		/*
806 		 * If the spool file exists, it better have the right owner
807 		 * and permissions!
808 		 */
809 
810 		if (Restart && noSpool()) {
811 			if ((! stat(Dfile, &stbuf)) &&
812 			    ((stbuf.st_mode != (DFILEMODE|S_IFREG)) ||
813 			    ((stbuf.st_gid != UUCPGID) ||
814 			     (stbuf.st_uid != UUCPUID)))) {
815 			    WMESG(SNDFILE, EM_NOTMP); /* I(slave) see bad perms */
816 			    logent("BAD DESTFILE OWNER/PERMS", "FAILED");
817 			    CDEBUG(1, "Failed: bad dest file owner/perms 0%o\n", stbuf.st_mode);
818 			    goto top;
819 			}
820 		}
821 		if ( ((fp = fopen(Dfile, "a+")) == NULL) || nospace(Dfile) ) {
822 			WMESG(SNDFILE, EM_NOTMP); /* I(slave) can't create TM file */
823 			logent("CAN'T OPEN", "DENIED");
824 			CDEBUG(1, "Failed: Can't Create Temp File\n%s", "");
825 			unlinkdf(Dfile);
826 			goto top;
827 		}
828 		chmod(Dfile, DFILEMODE);	/* no peeking! */
829 		chown(Dfile, UUCPUID, UUCPGID);
830 		if (Restart && (strlen(W_DFILE) > (size_t) 6)) {
831 		    if(fstat(fileno(fp), &stbuf)) {
832 			WMESG(SNDFILE, EM_NOTMP);
833 			logent("CAN'T STAT", "DENIED");
834 			CDEBUG(1, "Failed: Can't Stat Temp File\n%s", "");
835 			unlinkdf(Dfile);
836 			Seqn++;
837 			goto top;
838 		    }
839 		    /*
840 		     * find a good start point.  Take care of simple underflow
841 		     * and the signed nature of longs.
842 		     */
843 
844 		    DEBUG(7, "Dfile length 0x%lx\n", stbuf.st_size);
845 		    startp = stbuf.st_size - (stbuf.st_size % BUFSIZ);
846 		    if((stbuf.st_size >= 0) && (startp < 0))
847 			startp = 0;
848 
849 		    if(startp)
850 		    {
851 			if(startp < 0)
852 			    sprintf(tbuf,"start=0x%lx", startp);
853 			else
854 			    sprintf(tbuf,"start=%ld", startp);
855 
856 			logent(tbuf, "RESTART");
857 		    }
858 
859 		    sprintf(tbuf, "%s 0x%lx", YES, startp);
860 		    if (lseek(fileno(fp), startp, 0) == -1) {
861 			WMESG(SNDFILE, EM_SEEK);
862 			logent("CAN'T SEEK", "DENIED");
863 			CDEBUG(1, "Failed, Can't seek in Dfile\n%s", "");
864 			unlinkdf(Dfile);
865 			Seqn++;
866 			goto top;
867 		    }
868 		    fp->_cnt = 0;
869 		    fp->_ptr = fp->_base;
870 		    CDEBUG(1," restart msg %s\n", tbuf);
871 		    WMESG(SNDFILE, tbuf);
872 		}
873 		else
874 		    WMESG(SNDFILE, YES);	/* I(slave) clear to send */
875 		(void) millitick();	/* start msec timer */
876 		pfStrtXfer(SCHAR, RCVFILE);
877 		scStime(); 	/* log start transfer time for security log */
878 		/* (ret != 0) implies the trammission error occurred.
879      	           If checkpoint protocol is available then the next
880 		   recieve will restart from the breakpoint of the file,
881 		   otherwise from the beginning of the file  */
882 
883 		setline(RCVFILE);
884 		ret = (*Rddata)(Ifn, fp);
885 		setline(SNDFILE);
886 
887 		/* the second millitick() returns the duration between
888 		   the first and second call.
889    		   writes "PARTIAL FILE to the transfer log indicating
890 		   a transmission error. */
891 
892 		statlog( "<-", getfilesize(), millitick(),
893 				(ret) ? "PARTIAL FILE" : ""  );
894 
895 		pfEndXfer();
896 		scEtime();	/* log end transfer time for security log */
897 		Seqn++;
898 
899 		if (ret != 0) {
900 			pfEndfile("PARTIAL FILE");
901 			(void) fclose(fp);
902 			if ( ret == EFBIG ) {
903 				WMESG(RQSTCMPT, EM_ULIMIT);
904 				logent("FILE EXCEEDS ULIMIT","FAILED");
905 				CDEBUG(1, "Failed: file size exceeds ulimit%s\n", "");
906 				goto top;
907 			}
908 			(*Turnoff)();
909 			logent("INPUT FAILURE", "IN SEND/SLAVE MODE");
910 			return(FAIL);
911 		}
912 		if (Restart && (actualsize != -1)) {
913 		    if (fstat(fileno(fp), &stbuf)) {
914 			(void) fclose(fp);
915 			unlinkdf(Dfile);
916 			(*Turnoff)();
917 			logent("CAN'T STAT PFILE", "FAILED");
918 			return(FAIL);
919 		    }
920 		    if (stbuf.st_size != actualsize) {
921 			(void) fclose(fp);
922 			unlinkdf(Dfile);
923 			(*Turnoff)();
924 			logent("RECEIVED SIZE NOT EQUAL TO ACTUAL SIZE", "FAILED");
925 			CDEBUG(1, "Failed: receive size %ld ", stbuf.st_size);
926 			CDEBUG(1, "not equal to actual size %ld\n", actualsize);
927 			return(FAIL);
928 		    }
929 		}
930 		(void) fclose(fp);
931 
932 		/* copy to user directory */
933 		ntfyopt = strchr(W_OPTNS, 'n') != NULL;
934 
935 		/*
936 		 * See if spool file and target file in the same file system
937 		 */
938 
939 		ret = 0;
940 		if (p = strrchr(Dfile, '/'))
941 		{
942 			*p = '\0';
943 			ret = PREFIX(Dfile, filename);
944 			*p = '/';
945 		}
946 
947 		if (noSpool() && ret)
948 		{
949 		    /*
950 		     * if we are not already in the right file, and
951 		     * it is theoretically in the same file system,
952 		     * link it there...
953 		     */
954 
955 		    if(strcmp (filename, Dfile)) {
956 			    unlink(filename);
957 			    if(link(Dfile, filename))
958 			    {
959 				logent("FAILED", "MOVE");
960 				scWrite();
961 				putinpub(filename, Dfile, BASENAME(W_USER,'!'));
962 			    }
963 			    else
964 	    			DEBUG(7, "linked Point file to %s\n", filename);
965 			    unlink(Dfile);
966 		    }
967 		    else
968 		    	DEBUG(7, "Point file and %s the same\n", filename);
969 		    status = 0;			/* all done */
970 		}
971 		else
972 		    status = xmv(Dfile, filename);
973 
974 		scSize(Dfile);	/* log source file size */
975 		WMESG(RQSTCMPT, status ? EM_RMTCP : YES);
976 		if (status == 0) {
977 			sscanf(W_MODE, "%lo", &lfilemode);
978 			if (lfilemode <= 0)
979 				filemode = PUB_FILEMODE;
980 			else
981 				filemode = (mode_t)lfilemode;
982 			if (PREFIX(RemSpool, filename))
983 			    chmod(filename, DFILEMODE);
984 			else
985 			    chmod(filename, (filemode & LEGALMODE) | PUB_FILEMODE);
986 			arrived(ntfyopt, filename, W_NUSER, Rmtname, User);
987 		} else {
988 			logent("FAILED",  "COPY");
989 			scWrite();	/* log the security violation */
990 			status = putinpub(filename, Dfile,
991 			    BASENAME(W_USER, '!'));
992 			DEBUG(4, "->PUBDIR %d\n", status);
993 			if (status == 0)
994 				arrived(ntfyopt, filename, W_NUSER,
995 				    Rmtname, User);
996 		}
997 		pfEndfile("");	/* "" indicates the file transfer completely */
998 		if ( W_FILE2[1] == '.'  &&
999 		    (W_FILE2[0] == XQTPRE || W_FILE2[0] == DATAPRE) )
1000 			uuxqtflag = 1;
1001 		goto top;
1002 
1003 	case RCVFILE:
1004 
1005 		/*
1006 		 * MASTER section of RCVFULE
1007 		 */
1008 		DEBUG(4, "%s\n", "RCVFILE:");
1009 		if (msg[1] == 'N') {
1010 			i = atoi(&msg[2]);
1011 			if (i < 0 || i > EM_MAX)
1012 				i = 0;
1013 			logent(Em_msg[i], "REQUEST");
1014 		        notify(mailopt, W_USER, rqstr, Rmtname, &msg[1]);
1015 			ASSERT(Role == MASTER, Wr_ROLE, "", Role);
1016 			(void) fclose(fp);
1017 			unlinkdf(Dfile);
1018 		    	scWrite();	/* something is wrong on other side,
1019 					   log the security violation */
1020 			goto top;
1021 		}
1022 
1023 		if (msg[1] == 'Y') {
1024 
1025 		/* MASTER gets the original filesize from sender (SLAVE) */
1026 		/* This will be used to check the length of the P. file */
1027 			if (Restart) {
1028 			    *fsize = '\0';
1029 			    sscanf(&msg[2], "%*o %s", fsize);
1030 			    if (*fsize != '\0') {
1031 				actualsize = strtol(fsize, (char **) 0, FLENRADIX);
1032 				CDEBUG(7, "Actual File Length %ld\n", actualsize);
1033 			    } else {
1034 				actualsize = -1;
1035 				CDEBUG(7, "Actual File Length Not Provided\n%s", "");
1036 			    }
1037 			}
1038 
1039 			/*
1040 			 * receive file
1041 			 */
1042 			ASSERT(Role == MASTER, Wr_ROLE, "", Role);
1043 			(void) millitick();	/* start msec timer */
1044 			pfStrtXfer(MCHAR, SNDFILE);
1045 			scStime();
1046 		/* (ret != 0) implies the trammission error occurred.
1047      	           If checkpoint protocol is available then the next
1048 		   recieve will restart from the breakpoint of the file,
1049 		   otherwise from the beginning of the file  */
1050 
1051 			ret = (*Rddata)(Ifn, fp);
1052 
1053 		/* the second millitick() returns the duration between
1054 		   the first and second call.
1055    		   writes "PARTIAL FILE to the transfer log indicating
1056 		   a transmission error. */
1057 
1058 			statlog( "<-", getfilesize(), millitick(),
1059 				(ret) ? "PARTIAL FILE" : ""  );
1060 			pfEndXfer();
1061 			scEtime();
1062 			if (ret != 0) {
1063 				pfEndfile("PARTIAL FILE");
1064 				(void) fclose(fp);
1065 				if ( ret == EFBIG ) {
1066 					WMESG(RQSTCMPT, EM_ULIMIT);
1067 					logent("FILE EXCEEDS ULIMIT","FAILED");
1068 					CDEBUG(1, "Failed: file size exceeds ulimit%s\n", "");
1069 					goto top;
1070 				}
1071 				(*Turnoff)();
1072 				logent("INPUT FAILURE", "IN RECEIVE/MASTER MODE");
1073 				return(FAIL);
1074 			}
1075 			if (Restart && (actualsize != -1)) {
1076 			    if (fstat(fileno(fp), &stbuf)) {
1077 				(void) fclose(fp);
1078 				unlinkdf(Dfile);
1079 				(*Turnoff)();
1080 				logent("CAN'T STAT PFILE", "FAILED");
1081 				return(FAIL);
1082 			    }
1083 			    if (stbuf.st_size != actualsize) {
1084 				(void) fclose(fp);
1085 				unlinkdf(Dfile);
1086 				(*Turnoff)();
1087 				logent("RECEIVED SIZE NOT EQUAL TO ACTUAL SIZE", "FAILED");
1088 				CDEBUG(1, "Failed: receive size %ld ", stbuf.st_size);
1089 				CDEBUG(1, "not equal to actual size %ld\n", actualsize);
1090 				return(FAIL);
1091 			    }
1092 			}
1093 			(void) fclose(fp);
1094 
1095 			/*
1096 			 * See if spool file and target file in the same file system
1097 			 */
1098 
1099 			ret = 0;
1100 			if (p = strrchr(Dfile, '/'))
1101 			{
1102 				*p = '\0';
1103 				ret = PREFIX(Dfile, filename);
1104 				*p = '/';
1105 			}
1106 
1107 			if (noSpool() && ret)
1108 			{
1109 			    /*
1110 			     * if we are not already in the right file, and
1111 			     * it is theoretically in the same file system,
1112 			     * link it there...
1113 			     */
1114 
1115 			    if(strcmp (filename, Dfile)) {
1116 				    unlink(filename);
1117 				    if(link(Dfile, filename))
1118 				    {
1119 					logent("FAILED", "MOVE");
1120 					scWrite();
1121 					putinpub(filename, Dfile, W_USER);
1122 				    }
1123 				    else
1124 					DEBUG(7, "linked Point file to %s\n", filename);
1125 				    unlink(Dfile);
1126 			    }
1127 			    else
1128 				DEBUG(7, "Point file and %s the same\n", filename);
1129 			    status = 0;			/* all done */
1130 			}
1131 			else
1132 			    status = xmv(Dfile, filename);
1133 
1134 			WMESG(RQSTCMPT, status ? EM_RMTCP : YES);
1135 			notify(mailopt, W_USER, rqstr, Rmtname,
1136 			    status ? EM_LOCCP : YES);
1137 			if (status == 0) {
1138 			    sscanf(&msg[2], "%lo", &lfilemode);
1139 			    if (lfilemode <= 0)
1140 				filemode = PUB_FILEMODE;
1141 			    else
1142 				filemode = (mode_t)lfilemode;
1143 			    if (PREFIX(RemSpool, filename))
1144 				chmod(filename, DFILEMODE);
1145 			    else
1146 				chmod(filename, (filemode & LEGALMODE) | PUB_FILEMODE);
1147 			} else {
1148 			    logent("FAILED", "COPY");
1149 		    	    scWrite();	/* log the security violation */
1150 			    putinpub(filename, Dfile, W_USER);
1151 			}
1152 			pfEndfile("");	/* "" indicates the file transfer completely */
1153 			if ( W_FILE2[1] == '.'  &&
1154 			    (W_FILE2[0] == XQTPRE || W_FILE2[0] == DATAPRE) )
1155 				uuxqtflag = 1;
1156 			goto top;
1157 		}
1158 
1159 		/*
1160 		 * SLAVE section of RCVFILE
1161 		 * (request to send file)
1162 		 */
1163 		ASSERT(Role == SLAVE, Wr_ROLE, "", Role);
1164 
1165 		/* check permissions */
1166 		i = getargs(msg, wrkvec, W_MAX);
1167 
1168 		scRequser(W_USER); /* log requestor user id */
1169 
1170 		/* log destination node, user and file name */
1171 
1172 		scDest(Rmtname,NOTAVAIL,W_FILE2);
1173 
1174 		/* log source node, file owner, file name, mod time and size */
1175 
1176 		scSrc(Myname,scOwn(W_FILE1),W_FILE1,scMtime(W_FILE1),scSize(W_FILE1));
1177 		/* Check for bad request */
1178 		if (i < 5) {
1179 			WMESG(RCVFILE, EM_BADUUCP); /* you(remote master) gave me
1180 							bad work file */
1181 			logent("DENIED", "TOO FEW ARGS IN SLAVE RCVFILE");
1182 			goto top;
1183 		}
1184 
1185 		(void) sprintf(rqstr, "%s!%s --> %s!%s (%s)", Myname,
1186 			    W_FILE1, Rmtname, W_FILE2, W_USER);
1187 		logent(rqstr, "REMOTE REQUESTED");
1188 		CDEBUG(1, "Remote Requested: %s\n", rqstr);
1189 		mf = W_RFILE;
1190 		DEBUG(4, "msg - %s\n", msg);
1191 		DEBUG(4, "W_FILE1 - %s\n", W_FILE1);
1192 		(void) strcpy(filename, W_FILE1);
1193 		expfile(filename);
1194 		if (DIRECTORY(filename)) {
1195 			(void) strcat(filename, "/");
1196 			(void) strcat(filename, BASENAME(W_FILE2, '/'));
1197 		}
1198 		(void) sprintf(User, "%s", W_USER);
1199 
1200 		if (requestOK() == FALSE) {
1201 			/* remote can't request data from my system */
1202 			WMESG(RCVFILE, EM_RMTACC);
1203 			logent("DENIED", "REQUESTING");
1204 			CDEBUG(1, "Failed: Access Denied\n%s", "");
1205 		    	scWrite();	/* log the security violation */
1206 			goto top;
1207 		}
1208 		DEBUG(4, "requestOK for Loginuser - %s\n", Loginuser);
1209 
1210 		if ((fp = fopen(filename, "r")) == NULL) {
1211 			WMESG(RCVFILE, EM_RMTACC); /* you(remote master) can't
1212 							read my file */
1213 			logent("CAN'T OPEN", "DENIED");
1214 			CDEBUG(1, "Failed: Can't Open %s\n", filename);
1215 		    	scWrite();	/* log the security violation */
1216 			goto top;
1217 		}
1218 
1219 		if (chkpth(filename, CK_READ) || !F_READANY(fileno(fp))) {
1220 			WMESG(RCVFILE, EM_RMTACC); /* you(remote master) can't
1221 							retrive my file */
1222 			logent("DENIED", "PERMISSION");
1223 			CDEBUG(1, "Failed: Access Denied\n%s", "");
1224 		    	scWrite();	/* log the security violation */
1225 			fclose(fp);
1226 			goto top;
1227 		}
1228 		DEBUG(4, "chkpth ok Loginuser - %s\n", Loginuser);
1229 
1230 		ASSERT(fstat(fileno(fp), &stbuf) == 0, Ct_STAT,
1231 		    filename, errno);
1232 
1233 		/* Check whether remote's ulimit is exceeded */
1234 		if (SizeCheck) {
1235 			if (((stbuf.st_size-1)/512 + 1) > RemUlimit) {
1236 				/* remote ulimit exceeded */
1237 				WMESG(RCVFILE, EM_ULIMIT);
1238 				logent("DENIED", "REMOTE ULIMIT EXCEEDED");
1239 				CDEBUG(1, "Denied: remote ulimit exceeded %s\n", filename);
1240 				scWrite();
1241 				(void) fclose(fp);
1242 				goto top;
1243 			}
1244 		}
1245 
1246 		/*
1247 		 * ok to send file
1248 		 */
1249 
1250 		if (Restart && i >= 10) {
1251 		    if (startp = strtol(W_POINT, (char **) 0, FLENRADIX)) {
1252 			CDEBUG(1,"Restart point=0x%lx\n", startp);
1253 			errno = 0;
1254 			if (lseek(fileno(fp), startp, 0) == -1) {
1255 			    WMESG(RCVFILE, EM_SEEK);
1256 			    logent(strerror(errno), "FSEEK ERROR");
1257 			    (void) fclose(fp);
1258 			    goto top;
1259 			}
1260 			fp->_cnt = 0;
1261 			fp->_ptr = fp->_base;
1262 			if(startp < 0)
1263 			    sprintf(tbuf,"start=0x%lx", startp);
1264 			else
1265 			    sprintf(tbuf,"start=%ld", startp);
1266 			p = tbuf + strlen(tbuf);
1267 			if (stbuf.st_size < 0)
1268 			    sprintf(p,", length=0x%lx", stbuf.st_size);
1269 			else
1270 			    sprintf(p,", length=%ld", stbuf.st_size);
1271 
1272 			logent(tbuf, "RESTART");
1273 		   }
1274 		}
1275 
1276 		if (Restart)
1277 			(void) sprintf(msg, "%s %lo 0x%lx", YES,
1278 				(long) (stbuf.st_mode & LEGALMODE),
1279 				(long) stbuf.st_size);
1280 		else
1281 			(void) sprintf(msg, "%s %lo", YES,
1282 				(long) (stbuf.st_mode & LEGALMODE));
1283 		WMESG(RCVFILE, msg); /* I(slave) send you my file now */
1284 		Seqn++;
1285 		(void) millitick();	/* start msec timer */
1286 		scStime();
1287 		pfStrtXfer(SCHAR, SNDFILE);
1288 		/* (ret != 0) implies the trammission error occurred.
1289      	           If checkpoint protocol is available then the next
1290 		   transfer will restart from the breakpoint of the file,
1291 		   otherwise from the beginning of the file  */
1292 
1293 		ret = (*Wrdata)(fp, Ofn);
1294 
1295 		/* the second millitick() returns the duration between
1296 		   the first and second call.
1297    		   writes "PARTIAL FILE to the transfer log indicating
1298 		   a transmission error. */
1299 
1300 		statlog( "->", getfilesize(), millitick(),
1301 					(ret) ? "PARTIAL FILE" : ""  );
1302 		pfEndXfer();
1303 		scEtime();
1304 
1305 		(void) fclose(fp);
1306 		if (ret != 0) {
1307 			pfEndfile("PARTIAL FILE");
1308 			(*Turnoff)();
1309 			return(FAIL);
1310 		}
1311 
1312 		/* loop depending on the size of the file */
1313 		/* give an extra try for each megabyte */
1314 		/* stbuf set in fstat several lines back  */
1315 		for (im = stbuf.st_size >> 10; im >= 0; --im) {
1316 		    if ((ret = rmesg(RQSTCMPT, msg)) == 0)
1317 			break;	/* got message */
1318 		}
1319 		if (ret != 0) {
1320 		    (*Turnoff)();
1321 		     return(FAIL);
1322 		}
1323 		goto process;
1324 	}
1325 	(*Turnoff)();
1326 	return(FAIL);
1327 }
1328 
1329 
1330 
1331 /*
1332  * read message
1333  * returns:
1334  *	0	-> success
1335  *	FAIL	-> failure
1336  */
1337 int
1338 rmesg(c, msg)
1339 char *msg, c;
1340 {
1341 	char str[50];
1342 
1343 	DEBUG(4, "rmesg - '%c' ", c);
1344 	if ((*Rdmsg)(msg, Ifn) != 0) {
1345 		DEBUG(4, "got %s\n", "FAIL");
1346 		(void) sprintf(str, "expected '%c' got FAIL", c);
1347 		logent(str, "BAD READ");
1348 		return(FAIL);
1349 	}
1350 	if (c != '\0' && msg[0] != c) {
1351 		DEBUG(4, "got %s\n", msg);
1352 		(void) sprintf(str, "expected '%c' got %s", c, msg);
1353 		logent(str, "BAD READ");
1354 		return(FAIL);
1355 	}
1356 	DEBUG(4, "got %s\n", msg);
1357 	return(0);
1358 }
1359 
1360 
1361 /*
1362  * write a message
1363  * returns:
1364  *	0	-> ok
1365  *	FAIL	-> ng
1366  */
1367 int
1368 wmesg(m, s)
1369 char *s, m;
1370 {
1371 	CDEBUG(4, "wmesg '%c'", m);
1372 	CDEBUG(4, "%s\n", s);
1373 	return((*Wrmsg)(m, s, Ofn));
1374 }
1375 
1376 
1377 /*
1378  * mail results of command
1379  * return:
1380  *	none
1381  */
1382 void
1383 notify(mailopt, user, msgin, sys, msgcode)
1384 char *user, *msgin, *sys;
1385 char *msgcode;
1386 {
1387 	int i;
1388 	char str[BUFSIZ];
1389 	char *msg;
1390 
1391 	DEBUG(4,"mailopt %d, ", mailopt);
1392 	DEBUG(4,"statfopt %d\n", statfopt);
1393 	if (statfopt == 0 && mailopt == 0 && *msgcode == 'Y')
1394 		return;
1395 	if (*msgcode == 'Y')
1396 		msg = "copy succeeded";
1397 	else {
1398 		i = atoi(msgcode + 1);
1399 		if (i < 1 || i > EM_MAX)
1400 			i = 0;
1401 		msg = Em_msg[i];
1402 	}
1403 	if(statfopt){
1404 		stmesg(msgin, msg);
1405 		return;
1406 	}
1407 	(void) sprintf(str, "REQUEST: %s\n(SYSTEM: %s)  %s\n",
1408 		msgin, sys, msg);
1409 	mailst(user, msg, str, "", "");
1410 	return;
1411 }
1412 
1413 /*
1414  * local notify
1415  * return:
1416  *	none
1417  */
1418 void
1419 lnotify(user, msgin, mesg)
1420 char *user, *msgin, *mesg;
1421 {
1422 	char mbuf[BUFSIZ];
1423 
1424 	if(statfopt){
1425 		stmesg(msgin, mesg);
1426 		return;
1427 	}
1428 	(void) sprintf(mbuf, "REQUEST: %s\n(SYSTEM: %s)  %s\n",
1429 		msgin, Myname, mesg);
1430 	mailst(user, mesg, mbuf, "", "");
1431 	return;
1432 }
1433 
1434 /*ARGSUSED*/
1435 static void
1436 stmesg(f, m)
1437 char	*f, *m;
1438 {
1439 #ifdef notdef
1440 	FILE	*Cf;
1441 	time_t	clock;
1442 	long	td, th, tm, ts;
1443 #endif
1444 	char msg[BUFSIZ];
1445 
1446 	DEBUG(4,"STMES %s\n",mf);
1447 	sprintf(msg, "STMESG - %s", mf);
1448 	logent("DENIED", msg);
1449 #ifdef notdef
1450 	/*
1451 	 * This code is a giant security hole.
1452 	 * No checking is done on what file is
1453 	 * written and chmod'ed.  For now we
1454 	 * just ifdef this out.
1455 	 */
1456 	if((Cf = fopen(mf, "a+")) == NULL){
1457 		chmod(mf, PUB_FILEMODE);
1458 		return;
1459 	}
1460 	(void) time(&clock);
1461 	(void) fprintf(Cf, "uucp job: %s (%s) ", Jobid, timeStamp());
1462 	td = clock - Nstat.t_qtime;
1463 	ts = td%60;
1464 	td /= 60;
1465 	tm = td%60;
1466 	td /= 60;
1467 	th = td;
1468 	(void) fprintf(Cf, "(%ld:%ld:%ld)\n%s\n%s\n\n", th, tm, ts, f, m);
1469 	(void) fclose(Cf);
1470 	chmod(mf, PUB_FILEMODE);
1471 #endif
1472 }
1473 
1474 /*
1475  * converse with the remote machine, agree upon a
1476  * protocol (if possible) and start the protocol.
1477  * return:
1478  *	SUCCESS	-> successful protocol selection
1479  *	FAIL	-> can't find common or open failed
1480  */
1481 int
1482 startup(void)
1483 {
1484 	extern void blptcl();
1485 	extern int fptcl();
1486 	char msg[BUFSIZ], str[BUFSIZ];
1487 
1488 	Rdmsg = imsg;
1489 	Wrmsg = omsg;
1490 	Turnoff = turnoff;
1491 	blptcl(str);
1492 	if (Role == MASTER) {
1493 		RMESG(SLTPTCL, msg);
1494 		if ( fptcl(&msg[1], str) == FAIL) {
1495 		    /* no protocol match */
1496 		    WMESG(USEPTCL, NO);
1497 		    return(FAIL);
1498 		} else {
1499 		    /* got protocol match */
1500 		    WMESG(USEPTCL, &msg[1]);
1501 		    return(stptcl(&msg[1]));
1502 		}
1503 	} else {
1504 		WMESG(SLTPTCL, str);
1505 		RMESG(USEPTCL, msg);
1506 		if ( fptcl(&msg[1], str) == FAIL ) {
1507 			return(FAIL);
1508 		} else {
1509 		    return(stptcl(&msg[1]));
1510 		}
1511 	}
1512 }
1513 
1514 /*
1515  * choose a protocol from the input string (str)
1516  * and return the found letter.
1517  * Use the MASTER string (valid) for order of selection.
1518  * return:
1519  *	'\0'		-> no acceptable protocol
1520  *	any character	-> the chosen protocol
1521  */
1522 int
1523 fptcl(str, valid)
1524 char *str, *valid;
1525 {
1526 	char *l;
1527 
1528 	DEBUG(9, "Slave protocol list(%s)\n", str);
1529 	DEBUG(9, "Master protocol list(%s)\n", valid);
1530 
1531 	for (l = valid; *l != '\0'; l++) {
1532 		if ( strchr(str, *l) != NULL) {
1533 		    *str = *l;
1534 		    *(str+1) = '\0';
1535 		    /* also update string with parms */
1536 		    strcpy(_Protocol, findProto(_Protocol, *str));
1537 		    return(SUCCESS);
1538 		}
1539 	}
1540 	return(FAIL);
1541 }
1542 
1543 /*
1544  * build a string of the letters of the available
1545  * protocols and return the string (str).  The string consists of protocols
1546  * that are specified in the Systems and Devices files.  If nothing was
1547  * specified in those files, then the string is the list of protocols from
1548  * our Ptble.
1549  *
1550  *	str =		place to put the protocol list
1551  *	length =	size of buffer at str
1552  *
1553  * return:
1554  *	a pointer to string (str)
1555  */
1556 void
1557 blptcl(str)
1558 char *str;
1559 {
1560 	struct Proto *p;
1561 	char *validPtr;
1562 
1563 	/* Build list of valid protocols. */
1564 	for (validPtr = str, p = Ptbl; (*validPtr = p->P_id) != NULLCHAR;
1565 		validPtr++, p++);
1566 
1567 	/* Build _Protocol */
1568 	(void) protoString(str);	/* Get desired protocols. */
1569 	return;
1570 }
1571 
1572 /*
1573  * set up the six routines (Rdmg. Wrmsg, Rddata
1574  * Wrdata, Turnon, Turnoff) for the desired protocol.
1575  * returns:
1576  *	SUCCESS 	-> ok
1577  *	FAIL		-> no find or failed to open
1578  */
1579 int
1580 stptcl(c)
1581 char *c;
1582 {
1583 	struct Proto *p;
1584 
1585 	for (p = Ptbl; p->P_id != '\0'; p++) {
1586 		if (*c == p->P_id) {
1587 
1588 			/*
1589 			 * found protocol
1590 			 * set routine
1591 			 */
1592 			Rdmsg = p->P_rdmsg;
1593 			Wrmsg = p->P_wrmsg;
1594 			Rddata = p->P_rddata;
1595 			Wrdata = p->P_wrdata;
1596 			Turnon = p->P_turnon;
1597 			Turnoff = p->P_turnoff;
1598 			if ((*Turnon)() != 0)
1599 				break;
1600 			CDEBUG(4, "Proto started %c\n", *c);
1601 			pfPtcl(c);
1602 			return(SUCCESS);
1603 		}
1604 	}
1605 	CDEBUG(4, "Proto start-fail %c\n", *c);
1606 	return(FAIL);
1607 }
1608 
1609 /*
1610  * unlink D. file
1611  * returns:
1612  *	none
1613  */
1614 void
1615 unlinkdf(file)
1616 char *file;
1617 {
1618 	if (strlen(file) > (size_t) 6)
1619 		(void) unlink(file);
1620 	return;
1621 }
1622 
1623 /*
1624  * notify receiver of arrived file
1625  * returns:
1626  *	none
1627  */
1628 void
1629 arrived(opt, file, nuser, rmtsys, rmtuser)
1630 char *file, *nuser, *rmtsys, *rmtuser;
1631 {
1632 	char mbuf[200];
1633 
1634 	if (!opt)
1635 		return;
1636 	(void) sprintf(mbuf, "%s from %s!%s arrived\n", file, rmtsys, rmtuser);
1637 	mailst(nuser, mbuf, mbuf, "", "");
1638 	return;
1639 }
1640 
1641 
1642 /*
1643  * Check to see if there is space for file
1644  */
1645 
1646 #define FREESPACE 50  /* Minimum freespace in blocks to permit transfer */
1647 #define FREENODES 5   /* Minimum number of inodes to permit transfer */
1648 
1649 /*ARGSUSED*/
1650 static int
1651 nospace(name)
1652 char *name;
1653 #ifdef NOUSTAT
1654 {return(FALSE);}
1655 #else
1656 {
1657 	struct stat statb;
1658 #ifdef STATFS
1659 	struct statfs statfsb;
1660 #else
1661 	struct ustat ustatb;
1662 #endif
1663 
1664 	if( stat(name, &statb) < 0 )
1665 		return(TRUE);
1666 #ifdef	RT
1667 	if( (statb.st_mode|S_IFMT) == S_IFREG ||
1668 	    (statb.st_mode|S_IFMT) == S_IFEXT ||
1669 	    (statb.st_mode&S_IFMT) == S_IF1EXT )
1670 #else
1671 	if( (statb.st_mode&S_IFMT) == S_IFREG )
1672 #endif
1673 	{
1674 #ifdef STATFS
1675 		if( statfs(name, &statfsb)<0 )
1676 #else
1677 		if( ustat(statb.st_dev, &ustatb)<0 )
1678 #endif
1679 			return(TRUE);
1680 #ifdef STATFS
1681 		/*
1682 		 * Use 512-byte blocks, because that's the unit "ustat" tends
1683 		 * to work in.
1684 		 */
1685 		if( ((statfsb.f_bavail*statfsb.f_bsize)/512) < FREESPACE )
1686 #else
1687 		if( ustatb.f_tfree < FREESPACE )
1688 #endif
1689 		{
1690 			logent("FREESPACE IS LOW","REMOTE TRANSFER DENIED - ");
1691 			return(TRUE);
1692 		}
1693 #ifdef STATFS
1694 		/*
1695 		 * The test for "> 0" is there because the @$%#@#@$ NFS
1696 		 * protocol doesn't pass the number of free files over the
1697 		 * wire, so "statfs" on an NFS file system always returns -1.
1698 		 */
1699 		if( statfsb.f_ffree > 0
1700 		    && statfsb.f_ffree < FREENODES )
1701 #else
1702 		if( ustatb.f_tinode < FREENODES )
1703 #endif
1704 		{
1705 			logent("TOO FEW INODES","REMOTE TRANSFER DENIED - ");
1706 			return(TRUE);
1707 		}
1708 	}
1709 	return(FALSE);
1710 }
1711 #endif
1712 
1713 #ifdef V7USTAT
1714 int
1715 ustat(dev, ustat)
1716 int	dev;
1717 struct ustat *ustat;
1718 {
1719 	FILE	*dfp, *popen();
1720 	char	*fval, buf[BUFSIZ];
1721 
1722 	sprintf(buf, "%s %d %d 2>&1", V7USTAT, major(dev), minor(dev));
1723 	if ((dfp = popen(buf, "r")) == NULL)
1724 		return(-1);
1725 	fval = fgets(buf, sizeof(buf), dfp);
1726 	if (pclose(dfp) != 0
1727 	 || fval == NULL
1728 	 || sscanf(buf, "%d %d", &ustat->f_tfree, &ustat->f_tinode) != 2)
1729 		return(-1);
1730 	return(0);
1731 }
1732 #endif	/* V7USTAT */
1733