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