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