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
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.
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]
23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
28 /* All Rights Reserved */
34 void notify(), lnotify(), unlinkdf(), arrived();
48 extern char _Protocol
[];
49 extern char *findProto();
51 extern char uuxqtarg
[];
53 extern int gturnon(), gturnoff();
54 extern int grdmsg(), grddata();
55 extern int gwrmsg(), gwrdata();
57 extern int wmesg(), rmesg(), expfile(), putinpub(), stptcl();
58 extern void setline(), TMname(), cleanup(), pfEndfile(), statlog(), mailst();
61 extern int dturnon(), dturnoff();
62 extern int drdmsg(), drddata();
63 extern int dwrmsg(), dwrdata();
64 #endif /* D_PROTOCOL */
67 extern int xturnon(), xturnoff();
68 extern int xrdmsg(), xrddata();
69 extern int xwrmsg(), xwrdata();
70 #endif /* X_PROTOCOL */
73 extern int eturnon(), eturnoff();
74 extern int erdmsg(), erddata();
75 extern int ewrmsg(), ewrdata();
76 extern int trdmsg(), twrmsg();
77 extern int trddata(), twrdata();
78 #endif /* E_PROTOCOL */
81 extern int fturnon(), fturnoff();
82 extern int frdmsg(), frddata();
83 extern int fwrmsg(), fwrdata();
84 #endif /* F_PROTOCOL */
92 {'g', gturnon
, grdmsg
, gwrmsg
, grddata
, gwrdata
, gturnoff
},
93 {'G', gturnon
, grdmsg
, gwrmsg
, grddata
, gwrdata
, gturnoff
},
96 {'e', eturnon
, erdmsg
, ewrmsg
, erddata
, ewrdata
, eturnoff
},
97 {'t', eturnon
, trdmsg
, twrmsg
, trddata
, twrdata
, eturnoff
},
98 #endif /* E_PROTOCOL */
101 {'d', dturnon
, drdmsg
, dwrmsg
, drddata
, dwrdata
, dturnoff
},
102 #endif /* D_PROTOCOL */
105 {'x', xturnon
, xrdmsg
, xwrmsg
, xrddata
, xwrdata
, xturnoff
},
106 #endif /* X_PROTOCOL */
109 {'f', fturnon
, frdmsg
, fwrmsg
, frddata
, fwrdata
, fturnoff
},
110 #endif /* F_PROTOCOL */
114 #define VALIDSIZE sizeof(Ptbl)/sizeof(struct Proto)
116 int (*Rdmsg
)()=imsg
, (*Rddata
)();
117 int (*Wrmsg
)()=omsg
, (*Wrdata
)();
118 int (*Turnon
)(), (*Turnoff
)()=turnoff
;
124 #define TBUFSIZE 128 /* temporary buffer size */
125 #define FLENRADIX (16) /* output radix for file start point */
131 #define EM_LOCACC "N1" /* local access to file denied */
132 #define EM_RMTACC "N2" /* remote access to file/path denied */
133 #define EM_BADUUCP "N3" /* a bad uucp command was generated */
134 #define EM_NOTMP "N4" /* remote error - can't create temp */
135 #define EM_RMTCP "N5" /* can't copy to remote directory - file in public */
136 #define EM_LOCCP "N6" /* can't copy on local system */
137 #define EM_SEEK "N7" /* can't seek to checkpoint */
138 /* EM_ "N8" */ /* placeholder*/
139 /* EM_ "N9" */ /* placeholder*/
140 #define EM_ULIMIT "N10" /* receiver ulimit exceeded */
143 "COPY FAILED (reason not given by remote)",
144 "local access to file denied",
145 "remote access to path/file denied",
146 "system error - bad uucp command generated",
147 "remote system can't create temp file",
148 "can't copy to file/directory - file left in PUBDIR/user/file",
149 "can't copy to file/directory - file left in PUBDIR/user/file",
150 "can't seek to checkpoint",
151 "COPY FAILED (reason not given by remote)", /* placeholder */
152 "COPY FAILED (reason not given by remote)", /* placeholder */
153 "file exceeds ulimit of receiving system",
158 #define XUUCP 'X' /* execute uucp (string) */
159 #define SLTPTCL 'P' /* select protocol (string) */
160 #define USEPTCL 'U' /* use protocol (character) */
161 #define RCVFILE 'R' /* receive file (string) */
162 #define SNDFILE 'S' /* send file (string) */
163 #define RQSTCMPT 'C' /* request complete (string - yes | no) */
164 #define HUP 'H' /* ready to hangup (string - yes | no) */
165 #define RESET 'X' /* reset line modes */
167 #define W_MAX 10 /* maximum number of C. files per line */
168 #define W_MIN 7 /* min number of entries */
169 #define W_TYPE wrkvec[0]
170 #define W_FILE1 wrkvec[1]
171 #define W_FILE2 wrkvec[2]
172 #define W_USER wrkvec[3]
173 #define W_OPTNS wrkvec[4]
174 #define W_DFILE wrkvec[5]
175 #define W_MODE wrkvec[6]
176 #define W_NUSER wrkvec[7]
177 #define W_SFILE wrkvec[8]
178 #define W_RDFILE wrkvec[8]
179 #define W_POINT wrkvec[9]
180 #define W_FSIZE wrkvec[9]
181 #define W_RFILE wrkvec[5]
182 #define W_XFILE wrkvec[5]
185 #define RMESG(m, s) if (rmesg(m, s) != 0) {(*Turnoff)(); return(FAIL);}
186 #define RAMESG(s) if (rmesg('\0', s) != 0) {(*Turnoff)(); return(FAIL);}
187 #define WMESG(m, s) if(wmesg(m, s) != 0) {(*Turnoff)(); return(FAIL);}
189 char Wfile
[MAXFULLNAME
] = {'\0'};
190 char Dfile
[MAXFULLNAME
];
192 char *wrkvec
[W_MAX
+1];
196 * Create restart point filename
200 Pname(fileid
, dfile
, direct
)
203 int direct
; /* indicates a direct delivery temp file nameneeded */
208 * If the file is direct delivery, then its name is:
210 * /dir/dir/dir/.Pnnnnnnnn
212 * in the target directory. We create this by replacing the
213 * name of the target file with the D.nnnnnn name from the
214 * work vector, and then overwriting the D. with .P
218 if (p
= strrchr(dfile
, '/')) { /* find the last slash */
220 strcpy(p
, fileid
); /* append D.nnnnn name to dir */
222 *p
= 'P'; /* replace beginning with .P */
223 DEBUG(7, "Point file (direct) =%s\n", dfile
);
227 strcpy(dfile
, RemSpool
);
229 p
= dfile
+ strlen(Dfile
);
230 strcat(dfile
, fileid
);
232 DEBUG(7, "Point file=%s\n", dfile
);
238 * execute the conversation between the two machines
239 * after both programs are running.
250 long startp
; /* checkpoint restart point */
251 long actualsize
; /* actual file size */
257 int mailopt
, ntfyopt
;
260 char rqstr
[BUFSIZ
]; /* contains the current request message */
262 char filename
[MAXFULLNAME
], wrktype
;
263 char fsize
[NAMESIZE
]; /* holds file size/checkpoint string */
264 char localname
[MAXFULLNAME
]; /* real local system name */
265 char Recspool
[MAXFULLNAME
]; /* spool area for slave uucico */
267 extern int uuxqtflag
; /* set if received X. or D. file */
271 (void) sprintf(Recspool
, "%s/%s", SPOOL
, Rmtname
);
273 (void) strcpy(User
, Uucp
);
276 DEBUG(4, "*** TOP *** - Role=%d, ", Role
);
278 if (Role
== MASTER
) {
284 if ((narg
= gtwvec(Wfile
, wrkvec
, W_MAX
)) == 0) {
285 acEnd(COMPLETE
); /*stop collecting accounting log */
286 WMESG(HUP
, ""); /* I(master) am done. want me to quit? */
290 DEBUG(7, "Wfile - %s,", Wfile
);
291 strncpy(Jobid
, BASENAME(Wfile
, '/')+2, NAMESIZE
);
292 Jobid
[NAMESIZE
-1] = '\0';
293 DEBUG(7, "Jobid = %s\n", Jobid
);
295 pfFound(Jobid
, W_OPTNS
, Nstat
.t_qtime
);
296 mailopt
= strchr(W_OPTNS
, 'm') != NULL
;
297 statfopt
= strchr(W_OPTNS
, 'o') != NULL
;
298 ntfyopt
= strchr(W_OPTNS
, 'n') != NULL
;
300 uucpname(localname
); /* get real local machine name */
301 acDojob(Jobid
, localname
, W_USER
);
302 scRequser(W_USER
); /* log requestor user id */
305 * We used to check for corrupt workfiles here (narg < 5),
306 * but we were doing it wrong, and besides, anlwrk.c is the
307 * appropriate place to do it.
310 (void) sprintf(User
, "%s", W_USER
);
311 if (wrktype
== SNDFILE
) {
312 (void) sprintf(rqstr
, "%s!%s --> %s!%s (%s)", Myname
,
313 W_FILE1
, Rmtname
, W_FILE2
, User
);
315 /* log destination node, user and file name */
317 scDest(Rmtname
,NOTAVAIL
,W_FILE2
);
319 /* log source node, file owner, file name, mod time and size */
321 scSrc(Myname
,scOwn(W_FILE1
),W_FILE1
,scMtime(W_FILE1
)
324 logent(rqstr
, "REQUEST");
325 CDEBUG(1, "Request: %s\n", rqstr
);
327 (void) strcpy(filename
, W_FILE1
);
329 (void) strcpy(Dfile
, W_DFILE
);
330 if ( (fp
= fopen(Dfile
, "r")) == NULL
) {
331 if ( (fp
= fopen(filename
, "r")) == NULL
) {
332 /* cannot read spool or original file */
334 lnotify(User
, rqstr
, "can't access");
335 (void) sprintf(msg
, "CAN'T READ %s %d",
337 logent(msg
, "FAILED");
338 CDEBUG(1, "Failed: Can't Read %s\n", filename
);
339 scWrite(); /* log the security violation */
342 /* ensure original file is publicly readable */
343 if ( !F_READANY(fileno(fp
)) ) {
345 logent("DENIED", "ACCESS");
347 lnotify(User
, rqstr
, "access denied");
348 CDEBUG(1, "Failed: Access Denied\n%s", "");
349 scWrite(); /* log the security violation */
355 if (Restart
&& !(fstat(fileno(fp
), &stbuf
))) {
356 (void) sprintf(fsize
, "0x%lx", stbuf
.st_size
);
357 W_FSIZE
= fsize
; /* set file size in vector */
360 /* Check whether remote's ulimit is exceeded */
362 if (((stbuf
.st_size
-1)/512 + 1) > RemUlimit
) {
363 /* remote ulimit exceeded */
365 lnotify(User
, rqstr
, "remote ulimit exceeded");
366 logent("DENIED", "REMOTE ULIMIT EXCEEDED");
367 CDEBUG(1, "Denied: remote ulimit exceeded %s\n", filename
);
375 if (wrktype
== RCVFILE
) {
376 (void) sprintf(rqstr
, "%s!%s --> %s!%s (%s)", Rmtname
,
377 W_FILE1
, Myname
, W_FILE2
, User
);
379 /* log destination node, user and file name */
381 scDest(Myname
,NOTAVAIL
,W_FILE2
);
383 /* log source node, file owner, file name, mod time and size */
385 scSrc(Rmtname
,NOTAVAIL
,W_FILE1
,NOTAVAIL
,NOTAVAIL
);
387 logent(rqstr
, "REQUEST");
388 CDEBUG(1, "Request: %s\n", rqstr
);
390 (void) strcpy(filename
, W_FILE2
);
392 /* change Wrkdir to SPOOL/Rmtname in case the file being
393 ** requested is needed for some remote execution.
396 (void) strcpy(Wrkdir
, Recspool
);
399 /* now change Wrkdir back to what it was
400 ** just being paranoid.
403 (void) strcpy(Wrkdir
, RemSpool
);
404 if (chkperm(W_FILE1
, filename
, strchr(W_OPTNS
, 'd'))) {
407 logent("DENIED", "ACCESS");
408 lnotify(User
, rqstr
, "access denied");
409 CDEBUG(1, "Failed: Access Denied--File: %s\n",
411 scWrite(); /* log the security violation */
416 * If we are not going to spool the file in the spool
417 * directory, just use the destination file name. If we
418 * are not supporting restart, wipe out the target file.
421 * If restart is enabled, make up the Point file name
422 * as the file to open, else use the TM style name.
424 * If we run into a spool name of "D.0", this implies
425 * that someone forgot to install the new uucp and
426 * uux commands. Such jobs will not be checkpointed.
430 if (Restart
&& (strlen(W_RDFILE
) > (size_t) 6)) {
432 strcpy(Dfile
, filename
); /* use Dest file directly */
433 Pname(W_RDFILE
, Dfile
, TRUE
);
436 Pname(W_RDFILE
, Dfile
, FALSE
);
439 TMname(Dfile
, pnum
); /* get TM file name */
444 * If the spool file exists, it better have the right owner
448 if (Restart
&& noSpool()) {
449 if ((! stat(Dfile
, &stbuf
)) &&
450 ((stbuf
.st_mode
!= (DFILEMODE
|S_IFREG
)) ||
451 ((stbuf
.st_gid
!= UUCPGID
) ||
452 (stbuf
.st_uid
!= UUCPUID
)))) {
454 "bad spool file ownership/permissions");
455 logent("BAD DESTFILE OWNER/PERMS", "FAIL");
456 CDEBUG(1, "Failed: bad dest file owner/perms 0%o; fail\n", stbuf
.st_mode
);
460 if ( ((fp
= fopen(Dfile
, "a+")) == NULL
)
463 /* can not create temp */
465 logent("CAN'T CREATE/OPEN DEST FILE", "FAILED");
467 logent("CAN'T CREATE TM FILE", "FAILED");
468 CDEBUG(1, "Failed: No Space!\n%s", "");
470 assert(Ct_CREATE
, Dfile
, nospace(Dfile
),
476 * Send the W_POINT value to the other side.
480 if (fstat (fileno(fp
), &stbuf
)) {
481 logent("CAN'T STAT DFILE", "START FROM BEGINNING");
486 * find a good start point. Take care of simple
487 * underflow and the signed nature of longs.
490 DEBUG(7, "Dfile length 0x%lx\n", stbuf
.st_size
);
491 startp
= stbuf
.st_size
- (stbuf
.st_size
% BUFSIZ
);
492 if((stbuf
.st_size
>= 0) && (startp
< 0))
498 sprintf(tbuf
,"start=0x%lx", startp
);
500 sprintf(tbuf
,"start=%ld", startp
);
502 logent(tbuf
, "RESTART");
505 sprintf(fsize
, "0x%lx", startp
);
506 W_POINT
= fsize
; /* set start point in vector */
507 if (lseek(fileno(fp
), startp
, 0) == -1) {
508 WMESG(SNDFILE
, EM_SEEK
);
509 logent("CAN'T SEEK", "DENIED");
510 CDEBUG(1, "Failed, Can't seek in Dfile\n%s", "");
515 fp
->_ptr
= fp
->_base
;
519 chmod(Dfile
, DFILEMODE
); /* no peeking! */
520 chown(Dfile
, UUCPUID
, UUCPGID
);
523 DEBUG(4, "wrktype - %c\n ", wrktype
);
525 /* Build up the message itself */
528 for (i
= 1; i
< narg
; i
++) {
529 (void) strcat(msg
, " ");
530 (void) strcat(msg
, wrkvec
[i
]);
533 WMESG(wrktype
, msg
); /* I(master) am sending you our work file */
534 RMESG(wrktype
, msg
); /* I(master) am waiting for your response */
542 RAMESG(msg
); /* I(slave) am waiting for our work file */
546 DEBUG(4, " PROCESS: msg - %s\n", msg
);
550 DEBUG(4, "%s\n", "RQSTCMPT:");
553 if (i
< 0 || i
> EM_MAX
)
555 logent(Em_msg
[i
], "REQUESTED");
557 if (Role
== MASTER
) {
558 notify(mailopt
, W_USER
, rqstr
, Rmtname
, &msg
[1]);
560 pfEndfile(""); /* "" indicates the file transfer completely */
564 DEBUG(4, "%s\n", "HUP:");
566 WMESG(HUP
, YES
); /* let's quit */
575 ASSERT(Role
== MASTER
, Wr_ROLE
, "", Role
);
577 scReqsys(Rmtname
); /* log requestor system */
585 if ( (switchRole() == FALSE
) || !iswrk(Wfile
) ) {
586 DEBUG(5, "SLAVE-switchRole (%s)\n",
587 switchRole() ? "TRUE" : "FALSE");
588 WMESG(HUP
, YES
); /* let's quit */
593 /* Note that Wfile is the first C. to process at top
594 * set above by iswrk() call
600 WMESG(HUP
, NO
); /* don't quit. I(slave) have more to do */
602 uucpname(localname
); /* get real local machine name */
603 scReqsys(localname
); /* log requestor system */
619 * MASTER section of SNDFILE
621 DEBUG(4, "%s\n", "SNDFILE:");
625 if (i
< 0 || i
> EM_MAX
)
627 logent(Em_msg
[i
], "REQUEST");
628 notify(mailopt
, W_USER
, rqstr
, Rmtname
, &msg
[1]);
629 ASSERT(Role
== MASTER
, Wr_ROLE
, "", Role
);
631 /* if remote is out of tmp space, then just hang up */
632 ASSERT(i
!= 4, Em_msg
[4], Rmtname
, i
); /* EM_NOTMP */
634 scWrite(); /* something is wrong on other side,
635 log the security violation */
645 ASSERT(Role
== MASTER
, Wr_ROLE
, "", Role
);
646 if (fstat(fileno(fp
), &stbuf
)) /* never fail but .. */
647 stbuf
.st_size
= 0; /* for time loop calculation */
650 * If checkpoint restart is enabled, seek to the
651 * starting point in the file. We use hex because
652 * C doesn't support unsigned long directly.
656 if((startp
= strtol(&msg
[2], (char **) 0, FLENRADIX
))) {
657 CDEBUG(1, "Restart point=0x%lx\n", startp
);
659 sprintf(tbuf
,"start=0x%lx", startp
);
661 sprintf(tbuf
,"start=%ld", startp
);
662 p
= tbuf
+ strlen(tbuf
);
663 if (stbuf
.st_size
< 0)
664 sprintf(p
,", length=0x%lx", stbuf
.st_size
);
666 sprintf(p
,", length=%ld", stbuf
.st_size
);
668 logent(tbuf
, "RESTART");
670 if (lseek(fileno(fp
), startp
, 0) == -1) {
671 logent(strerror(errno
), "FSEEK ERROR");
678 fp
->_ptr
= fp
->_base
;
681 (void) millitick(); /* start msec timer */
682 pfStrtXfer(MCHAR
, SNDFILE
);
683 scStime(); /* log start transfer time for security log */
685 /* (ret != 0) implies the trammission error occurred.
686 If checkpoint protocol is available then the next
687 transfer will restart from the breakpoint of the file,
688 otherwise from the beginning of the file */
690 ret
= (*Wrdata
)(fp
, Ofn
);
692 /* the second millitick() returns the duration between
693 the first and second call.
694 writes "PARTIAL FILE to the transfer log indicating
695 a transmission error. */
697 statlog( "->", getfilesize(), millitick(),
698 (ret
) ? "PARTIAL FILE" : "" );
700 acInc(); /* increment job size in accounting log */
702 scEtime(); /* log end transfer time for security log */
706 pfEndfile("PARTIAL FILE");
707 acEnd(PARTIAL
); /*stop collecting accounting log */
712 /* loop depending on the size of the file */
713 /* give an extra try for each megabyte */
714 for (im
= stbuf
.st_size
>> 10; im
>= 0; --im
) {
715 if ((ret
= rmesg(RQSTCMPT
, msg
)) == 0)
716 break; /* got message */
727 * SLAVE section of SNDFILE
729 ASSERT(Role
== SLAVE
, Wr_ROLE
, "", Role
);
732 * request to receive file
735 i
= getargs(msg
, wrkvec
, W_MAX
);
737 scRequser(W_USER
); /* log requestor user id */
739 /* log destination node, user and file name */
741 scDest(Myname
,NOTAVAIL
,W_FILE2
);
743 /* log source node, file owner, file name, mod time and size */
745 scSrc(Rmtname
,NOTAVAIL
,W_FILE1
,NOTAVAIL
,NOTAVAIL
);
747 /* Check for bad request */
749 WMESG(SNDFILE
, EM_BADUUCP
); /* you(remote master) gave me
751 logent("DENIED", "TOO FEW ARGS IN SLAVE SNDFILE");
754 /* SLAVE gets the original filesize from sender (MASTER) */
755 /* This will be used to check the length of the P. file */
757 if (W_FSIZE
&& (*W_FSIZE
!= '\0')) {
758 actualsize
= strtol(W_FSIZE
, (char **) 0, FLENRADIX
);
759 CDEBUG(7, "Actual File Length %ld\n", actualsize
);
762 CDEBUG(7, "Actual File Length Not Provided\n%s", "");
767 (void) sprintf(rqstr
, "%s!%s --> %s!%s (%s)", Rmtname
,
768 W_FILE1
, Myname
, W_FILE2
, W_USER
);
769 logent(rqstr
, "REMOTE REQUESTED");
770 DEBUG(4, "msg - %s\n", msg
);
771 CDEBUG(1, "Remote Requested: %s\n", rqstr
);
772 (void) strcpy(filename
, W_FILE2
);
774 DEBUG(4, "SLAVE - filename: %s\n", filename
);
775 if (chkpth(filename
, CK_WRITE
)
776 || chkperm(W_FILE1
, filename
, strchr(W_OPTNS
, 'd'))) {
777 WMESG(SNDFILE
, EM_RMTACC
); /* you(remote master) can't
778 send data to this file(directory) */
779 logent("DENIED", "PERMISSION");
780 CDEBUG(1, "Failed: Access Denied\n%s", "");
781 scWrite(); /* log security violation */
784 (void) sprintf(User
, "%s", W_USER
);
786 DEBUG(4, "chkpth ok Rmtname - %s\n", Rmtname
);
790 if (Restart
&& (strlen(W_DFILE
) > (size_t) 6)) {
792 strcpy(Dfile
, filename
); /* use Dest file directly */
793 Pname(W_DFILE
, Dfile
, TRUE
);
798 Pname(W_DFILE
, Dfile
, FALSE
);
801 TMname(Dfile
, pnum
); /* get TM file name */
806 * If the spool file exists, it better have the right owner
810 if (Restart
&& noSpool()) {
811 if ((! stat(Dfile
, &stbuf
)) &&
812 ((stbuf
.st_mode
!= (DFILEMODE
|S_IFREG
)) ||
813 ((stbuf
.st_gid
!= UUCPGID
) ||
814 (stbuf
.st_uid
!= UUCPUID
)))) {
815 WMESG(SNDFILE
, EM_NOTMP
); /* I(slave) see bad perms */
816 logent("BAD DESTFILE OWNER/PERMS", "FAILED");
817 CDEBUG(1, "Failed: bad dest file owner/perms 0%o\n", stbuf
.st_mode
);
821 if ( ((fp
= fopen(Dfile
, "a+")) == NULL
) || nospace(Dfile
) ) {
822 WMESG(SNDFILE
, EM_NOTMP
); /* I(slave) can't create TM file */
823 logent("CAN'T OPEN", "DENIED");
824 CDEBUG(1, "Failed: Can't Create Temp File\n%s", "");
828 chmod(Dfile
, DFILEMODE
); /* no peeking! */
829 chown(Dfile
, UUCPUID
, UUCPGID
);
830 if (Restart
&& (strlen(W_DFILE
) > (size_t) 6)) {
831 if(fstat(fileno(fp
), &stbuf
)) {
832 WMESG(SNDFILE
, EM_NOTMP
);
833 logent("CAN'T STAT", "DENIED");
834 CDEBUG(1, "Failed: Can't Stat Temp File\n%s", "");
840 * find a good start point. Take care of simple underflow
841 * and the signed nature of longs.
844 DEBUG(7, "Dfile length 0x%lx\n", stbuf
.st_size
);
845 startp
= stbuf
.st_size
- (stbuf
.st_size
% BUFSIZ
);
846 if((stbuf
.st_size
>= 0) && (startp
< 0))
852 sprintf(tbuf
,"start=0x%lx", startp
);
854 sprintf(tbuf
,"start=%ld", startp
);
856 logent(tbuf
, "RESTART");
859 sprintf(tbuf
, "%s 0x%lx", YES
, startp
);
860 if (lseek(fileno(fp
), startp
, 0) == -1) {
861 WMESG(SNDFILE
, EM_SEEK
);
862 logent("CAN'T SEEK", "DENIED");
863 CDEBUG(1, "Failed, Can't seek in Dfile\n%s", "");
869 fp
->_ptr
= fp
->_base
;
870 CDEBUG(1," restart msg %s\n", tbuf
);
871 WMESG(SNDFILE
, tbuf
);
874 WMESG(SNDFILE
, YES
); /* I(slave) clear to send */
875 (void) millitick(); /* start msec timer */
876 pfStrtXfer(SCHAR
, RCVFILE
);
877 scStime(); /* log start transfer time for security log */
878 /* (ret != 0) implies the trammission error occurred.
879 If checkpoint protocol is available then the next
880 recieve will restart from the breakpoint of the file,
881 otherwise from the beginning of the file */
884 ret
= (*Rddata
)(Ifn
, fp
);
887 /* the second millitick() returns the duration between
888 the first and second call.
889 writes "PARTIAL FILE to the transfer log indicating
890 a transmission error. */
892 statlog( "<-", getfilesize(), millitick(),
893 (ret
) ? "PARTIAL FILE" : "" );
896 scEtime(); /* log end transfer time for security log */
900 pfEndfile("PARTIAL FILE");
902 if ( ret
== EFBIG
) {
903 WMESG(RQSTCMPT
, EM_ULIMIT
);
904 logent("FILE EXCEEDS ULIMIT","FAILED");
905 CDEBUG(1, "Failed: file size exceeds ulimit%s\n", "");
909 logent("INPUT FAILURE", "IN SEND/SLAVE MODE");
912 if (Restart
&& (actualsize
!= -1)) {
913 if (fstat(fileno(fp
), &stbuf
)) {
917 logent("CAN'T STAT PFILE", "FAILED");
920 if (stbuf
.st_size
!= actualsize
) {
924 logent("RECEIVED SIZE NOT EQUAL TO ACTUAL SIZE", "FAILED");
925 CDEBUG(1, "Failed: receive size %ld ", stbuf
.st_size
);
926 CDEBUG(1, "not equal to actual size %ld\n", actualsize
);
932 /* copy to user directory */
933 ntfyopt
= strchr(W_OPTNS
, 'n') != NULL
;
936 * See if spool file and target file in the same file system
940 if (p
= strrchr(Dfile
, '/'))
943 ret
= PREFIX(Dfile
, filename
);
947 if (noSpool() && ret
)
950 * if we are not already in the right file, and
951 * it is theoretically in the same file system,
955 if(strcmp (filename
, Dfile
)) {
957 if(link(Dfile
, filename
))
959 logent("FAILED", "MOVE");
961 putinpub(filename
, Dfile
, BASENAME(W_USER
,'!'));
964 DEBUG(7, "linked Point file to %s\n", filename
);
968 DEBUG(7, "Point file and %s the same\n", filename
);
969 status
= 0; /* all done */
972 status
= xmv(Dfile
, filename
);
974 scSize(Dfile
); /* log source file size */
975 WMESG(RQSTCMPT
, status
? EM_RMTCP
: YES
);
977 sscanf(W_MODE
, "%lo", &lfilemode
);
979 filemode
= PUB_FILEMODE
;
981 filemode
= (mode_t
)lfilemode
;
982 if (PREFIX(RemSpool
, filename
))
983 chmod(filename
, DFILEMODE
);
985 chmod(filename
, (filemode
& LEGALMODE
) | PUB_FILEMODE
);
986 arrived(ntfyopt
, filename
, W_NUSER
, Rmtname
, User
);
988 logent("FAILED", "COPY");
989 scWrite(); /* log the security violation */
990 status
= putinpub(filename
, Dfile
,
991 BASENAME(W_USER
, '!'));
992 DEBUG(4, "->PUBDIR %d\n", status
);
994 arrived(ntfyopt
, filename
, W_NUSER
,
997 pfEndfile(""); /* "" indicates the file transfer completely */
998 if ( W_FILE2
[1] == '.' &&
999 (W_FILE2
[0] == XQTPRE
|| W_FILE2
[0] == DATAPRE
) )
1006 * MASTER section of RCVFULE
1008 DEBUG(4, "%s\n", "RCVFILE:");
1009 if (msg
[1] == 'N') {
1011 if (i
< 0 || i
> EM_MAX
)
1013 logent(Em_msg
[i
], "REQUEST");
1014 notify(mailopt
, W_USER
, rqstr
, Rmtname
, &msg
[1]);
1015 ASSERT(Role
== MASTER
, Wr_ROLE
, "", Role
);
1018 scWrite(); /* something is wrong on other side,
1019 log the security violation */
1023 if (msg
[1] == 'Y') {
1025 /* MASTER gets the original filesize from sender (SLAVE) */
1026 /* This will be used to check the length of the P. file */
1029 sscanf(&msg
[2], "%*o %s", fsize
);
1030 if (*fsize
!= '\0') {
1031 actualsize
= strtol(fsize
, (char **) 0, FLENRADIX
);
1032 CDEBUG(7, "Actual File Length %ld\n", actualsize
);
1035 CDEBUG(7, "Actual File Length Not Provided\n%s", "");
1042 ASSERT(Role
== MASTER
, Wr_ROLE
, "", Role
);
1043 (void) millitick(); /* start msec timer */
1044 pfStrtXfer(MCHAR
, SNDFILE
);
1046 /* (ret != 0) implies the trammission error occurred.
1047 If checkpoint protocol is available then the next
1048 recieve will restart from the breakpoint of the file,
1049 otherwise from the beginning of the file */
1051 ret
= (*Rddata
)(Ifn
, fp
);
1053 /* the second millitick() returns the duration between
1054 the first and second call.
1055 writes "PARTIAL FILE to the transfer log indicating
1056 a transmission error. */
1058 statlog( "<-", getfilesize(), millitick(),
1059 (ret
) ? "PARTIAL FILE" : "" );
1063 pfEndfile("PARTIAL FILE");
1065 if ( ret
== EFBIG
) {
1066 WMESG(RQSTCMPT
, EM_ULIMIT
);
1067 logent("FILE EXCEEDS ULIMIT","FAILED");
1068 CDEBUG(1, "Failed: file size exceeds ulimit%s\n", "");
1072 logent("INPUT FAILURE", "IN RECEIVE/MASTER MODE");
1075 if (Restart
&& (actualsize
!= -1)) {
1076 if (fstat(fileno(fp
), &stbuf
)) {
1080 logent("CAN'T STAT PFILE", "FAILED");
1083 if (stbuf
.st_size
!= actualsize
) {
1087 logent("RECEIVED SIZE NOT EQUAL TO ACTUAL SIZE", "FAILED");
1088 CDEBUG(1, "Failed: receive size %ld ", stbuf
.st_size
);
1089 CDEBUG(1, "not equal to actual size %ld\n", actualsize
);
1096 * See if spool file and target file in the same file system
1100 if (p
= strrchr(Dfile
, '/'))
1103 ret
= PREFIX(Dfile
, filename
);
1107 if (noSpool() && ret
)
1110 * if we are not already in the right file, and
1111 * it is theoretically in the same file system,
1115 if(strcmp (filename
, Dfile
)) {
1117 if(link(Dfile
, filename
))
1119 logent("FAILED", "MOVE");
1121 putinpub(filename
, Dfile
, W_USER
);
1124 DEBUG(7, "linked Point file to %s\n", filename
);
1128 DEBUG(7, "Point file and %s the same\n", filename
);
1129 status
= 0; /* all done */
1132 status
= xmv(Dfile
, filename
);
1134 WMESG(RQSTCMPT
, status
? EM_RMTCP
: YES
);
1135 notify(mailopt
, W_USER
, rqstr
, Rmtname
,
1136 status
? EM_LOCCP
: YES
);
1138 sscanf(&msg
[2], "%lo", &lfilemode
);
1140 filemode
= PUB_FILEMODE
;
1142 filemode
= (mode_t
)lfilemode
;
1143 if (PREFIX(RemSpool
, filename
))
1144 chmod(filename
, DFILEMODE
);
1146 chmod(filename
, (filemode
& LEGALMODE
) | PUB_FILEMODE
);
1148 logent("FAILED", "COPY");
1149 scWrite(); /* log the security violation */
1150 putinpub(filename
, Dfile
, W_USER
);
1152 pfEndfile(""); /* "" indicates the file transfer completely */
1153 if ( W_FILE2
[1] == '.' &&
1154 (W_FILE2
[0] == XQTPRE
|| W_FILE2
[0] == DATAPRE
) )
1160 * SLAVE section of RCVFILE
1161 * (request to send file)
1163 ASSERT(Role
== SLAVE
, Wr_ROLE
, "", Role
);
1165 /* check permissions */
1166 i
= getargs(msg
, wrkvec
, W_MAX
);
1168 scRequser(W_USER
); /* log requestor user id */
1170 /* log destination node, user and file name */
1172 scDest(Rmtname
,NOTAVAIL
,W_FILE2
);
1174 /* log source node, file owner, file name, mod time and size */
1176 scSrc(Myname
,scOwn(W_FILE1
),W_FILE1
,scMtime(W_FILE1
),scSize(W_FILE1
));
1177 /* Check for bad request */
1179 WMESG(RCVFILE
, EM_BADUUCP
); /* you(remote master) gave me
1181 logent("DENIED", "TOO FEW ARGS IN SLAVE RCVFILE");
1185 (void) sprintf(rqstr
, "%s!%s --> %s!%s (%s)", Myname
,
1186 W_FILE1
, Rmtname
, W_FILE2
, W_USER
);
1187 logent(rqstr
, "REMOTE REQUESTED");
1188 CDEBUG(1, "Remote Requested: %s\n", rqstr
);
1190 DEBUG(4, "msg - %s\n", msg
);
1191 DEBUG(4, "W_FILE1 - %s\n", W_FILE1
);
1192 (void) strcpy(filename
, W_FILE1
);
1194 if (DIRECTORY(filename
)) {
1195 (void) strcat(filename
, "/");
1196 (void) strcat(filename
, BASENAME(W_FILE2
, '/'));
1198 (void) sprintf(User
, "%s", W_USER
);
1200 if (requestOK() == FALSE
) {
1201 /* remote can't request data from my system */
1202 WMESG(RCVFILE
, EM_RMTACC
);
1203 logent("DENIED", "REQUESTING");
1204 CDEBUG(1, "Failed: Access Denied\n%s", "");
1205 scWrite(); /* log the security violation */
1208 DEBUG(4, "requestOK for Loginuser - %s\n", Loginuser
);
1210 if ((fp
= fopen(filename
, "r")) == NULL
) {
1211 WMESG(RCVFILE
, EM_RMTACC
); /* you(remote master) can't
1213 logent("CAN'T OPEN", "DENIED");
1214 CDEBUG(1, "Failed: Can't Open %s\n", filename
);
1215 scWrite(); /* log the security violation */
1219 if (chkpth(filename
, CK_READ
) || !F_READANY(fileno(fp
))) {
1220 WMESG(RCVFILE
, EM_RMTACC
); /* you(remote master) can't
1222 logent("DENIED", "PERMISSION");
1223 CDEBUG(1, "Failed: Access Denied\n%s", "");
1224 scWrite(); /* log the security violation */
1228 DEBUG(4, "chkpth ok Loginuser - %s\n", Loginuser
);
1230 ASSERT(fstat(fileno(fp
), &stbuf
) == 0, Ct_STAT
,
1233 /* Check whether remote's ulimit is exceeded */
1235 if (((stbuf
.st_size
-1)/512 + 1) > RemUlimit
) {
1236 /* remote ulimit exceeded */
1237 WMESG(RCVFILE
, EM_ULIMIT
);
1238 logent("DENIED", "REMOTE ULIMIT EXCEEDED");
1239 CDEBUG(1, "Denied: remote ulimit exceeded %s\n", filename
);
1250 if (Restart
&& i
>= 10) {
1251 if (startp
= strtol(W_POINT
, (char **) 0, FLENRADIX
)) {
1252 CDEBUG(1,"Restart point=0x%lx\n", startp
);
1254 if (lseek(fileno(fp
), startp
, 0) == -1) {
1255 WMESG(RCVFILE
, EM_SEEK
);
1256 logent(strerror(errno
), "FSEEK ERROR");
1261 fp
->_ptr
= fp
->_base
;
1263 sprintf(tbuf
,"start=0x%lx", startp
);
1265 sprintf(tbuf
,"start=%ld", startp
);
1266 p
= tbuf
+ strlen(tbuf
);
1267 if (stbuf
.st_size
< 0)
1268 sprintf(p
,", length=0x%lx", stbuf
.st_size
);
1270 sprintf(p
,", length=%ld", stbuf
.st_size
);
1272 logent(tbuf
, "RESTART");
1277 (void) sprintf(msg
, "%s %lo 0x%lx", YES
,
1278 (long) (stbuf
.st_mode
& LEGALMODE
),
1279 (long) stbuf
.st_size
);
1281 (void) sprintf(msg
, "%s %lo", YES
,
1282 (long) (stbuf
.st_mode
& LEGALMODE
));
1283 WMESG(RCVFILE
, msg
); /* I(slave) send you my file now */
1285 (void) millitick(); /* start msec timer */
1287 pfStrtXfer(SCHAR
, SNDFILE
);
1288 /* (ret != 0) implies the trammission error occurred.
1289 If checkpoint protocol is available then the next
1290 transfer will restart from the breakpoint of the file,
1291 otherwise from the beginning of the file */
1293 ret
= (*Wrdata
)(fp
, Ofn
);
1295 /* the second millitick() returns the duration between
1296 the first and second call.
1297 writes "PARTIAL FILE to the transfer log indicating
1298 a transmission error. */
1300 statlog( "->", getfilesize(), millitick(),
1301 (ret
) ? "PARTIAL FILE" : "" );
1307 pfEndfile("PARTIAL FILE");
1312 /* loop depending on the size of the file */
1313 /* give an extra try for each megabyte */
1314 /* stbuf set in fstat several lines back */
1315 for (im
= stbuf
.st_size
>> 10; im
>= 0; --im
) {
1316 if ((ret
= rmesg(RQSTCMPT
, msg
)) == 0)
1317 break; /* got message */
1343 DEBUG(4, "rmesg - '%c' ", c
);
1344 if ((*Rdmsg
)(msg
, Ifn
) != 0) {
1345 DEBUG(4, "got %s\n", "FAIL");
1346 (void) sprintf(str
, "expected '%c' got FAIL", c
);
1347 logent(str
, "BAD READ");
1350 if (c
!= '\0' && msg
[0] != c
) {
1351 DEBUG(4, "got %s\n", msg
);
1352 (void) sprintf(str
, "expected '%c' got %s", c
, msg
);
1353 logent(str
, "BAD READ");
1356 DEBUG(4, "got %s\n", msg
);
1371 CDEBUG(4, "wmesg '%c'", m
);
1372 CDEBUG(4, "%s\n", s
);
1373 return((*Wrmsg
)(m
, s
, Ofn
));
1378 * mail results of command
1383 notify(mailopt
, user
, msgin
, sys
, msgcode
)
1384 char *user
, *msgin
, *sys
;
1391 DEBUG(4,"mailopt %d, ", mailopt
);
1392 DEBUG(4,"statfopt %d\n", statfopt
);
1393 if (statfopt
== 0 && mailopt
== 0 && *msgcode
== 'Y')
1395 if (*msgcode
== 'Y')
1396 msg
= "copy succeeded";
1398 i
= atoi(msgcode
+ 1);
1399 if (i
< 1 || i
> EM_MAX
)
1407 (void) sprintf(str
, "REQUEST: %s\n(SYSTEM: %s) %s\n",
1409 mailst(user
, msg
, str
, "", "");
1419 lnotify(user
, msgin
, mesg
)
1420 char *user
, *msgin
, *mesg
;
1425 stmesg(msgin
, mesg
);
1428 (void) sprintf(mbuf
, "REQUEST: %s\n(SYSTEM: %s) %s\n",
1429 msgin
, Myname
, mesg
);
1430 mailst(user
, mesg
, mbuf
, "", "");
1442 long td
, th
, tm
, ts
;
1446 DEBUG(4,"STMES %s\n",mf
);
1447 sprintf(msg
, "STMESG - %s", mf
);
1448 logent("DENIED", msg
);
1451 * This code is a giant security hole.
1452 * No checking is done on what file is
1453 * written and chmod'ed. For now we
1454 * just ifdef this out.
1456 if((Cf
= fopen(mf
, "a+")) == NULL
){
1457 chmod(mf
, PUB_FILEMODE
);
1460 (void) time(&clock
);
1461 (void) fprintf(Cf
, "uucp job: %s (%s) ", Jobid
, timeStamp());
1462 td
= clock
- Nstat
.t_qtime
;
1468 (void) fprintf(Cf
, "(%ld:%ld:%ld)\n%s\n%s\n\n", th
, tm
, ts
, f
, m
);
1470 chmod(mf
, PUB_FILEMODE
);
1475 * converse with the remote machine, agree upon a
1476 * protocol (if possible) and start the protocol.
1478 * SUCCESS -> successful protocol selection
1479 * FAIL -> can't find common or open failed
1484 extern void blptcl();
1486 char msg
[BUFSIZ
], str
[BUFSIZ
];
1492 if (Role
== MASTER
) {
1493 RMESG(SLTPTCL
, msg
);
1494 if ( fptcl(&msg
[1], str
) == FAIL
) {
1495 /* no protocol match */
1499 /* got protocol match */
1500 WMESG(USEPTCL
, &msg
[1]);
1501 return(stptcl(&msg
[1]));
1504 WMESG(SLTPTCL
, str
);
1505 RMESG(USEPTCL
, msg
);
1506 if ( fptcl(&msg
[1], str
) == FAIL
) {
1509 return(stptcl(&msg
[1]));
1515 * choose a protocol from the input string (str)
1516 * and return the found letter.
1517 * Use the MASTER string (valid) for order of selection.
1519 * '\0' -> no acceptable protocol
1520 * any character -> the chosen protocol
1528 DEBUG(9, "Slave protocol list(%s)\n", str
);
1529 DEBUG(9, "Master protocol list(%s)\n", valid
);
1531 for (l
= valid
; *l
!= '\0'; l
++) {
1532 if ( strchr(str
, *l
) != NULL
) {
1535 /* also update string with parms */
1536 strcpy(_Protocol
, findProto(_Protocol
, *str
));
1544 * build a string of the letters of the available
1545 * protocols and return the string (str). The string consists of protocols
1546 * that are specified in the Systems and Devices files. If nothing was
1547 * specified in those files, then the string is the list of protocols from
1550 * str = place to put the protocol list
1551 * length = size of buffer at str
1554 * a pointer to string (str)
1563 /* Build list of valid protocols. */
1564 for (validPtr
= str
, p
= Ptbl
; (*validPtr
= p
->P_id
) != NULLCHAR
;
1567 /* Build _Protocol */
1568 (void) protoString(str
); /* Get desired protocols. */
1573 * set up the six routines (Rdmg. Wrmsg, Rddata
1574 * Wrdata, Turnon, Turnoff) for the desired protocol.
1577 * FAIL -> no find or failed to open
1585 for (p
= Ptbl
; p
->P_id
!= '\0'; p
++) {
1586 if (*c
== p
->P_id
) {
1594 Rddata
= p
->P_rddata
;
1595 Wrdata
= p
->P_wrdata
;
1596 Turnon
= p
->P_turnon
;
1597 Turnoff
= p
->P_turnoff
;
1598 if ((*Turnon
)() != 0)
1600 CDEBUG(4, "Proto started %c\n", *c
);
1605 CDEBUG(4, "Proto start-fail %c\n", *c
);
1618 if (strlen(file
) > (size_t) 6)
1619 (void) unlink(file
);
1624 * notify receiver of arrived file
1629 arrived(opt
, file
, nuser
, rmtsys
, rmtuser
)
1630 char *file
, *nuser
, *rmtsys
, *rmtuser
;
1636 (void) sprintf(mbuf
, "%s from %s!%s arrived\n", file
, rmtsys
, rmtuser
);
1637 mailst(nuser
, mbuf
, mbuf
, "", "");
1643 * Check to see if there is space for file
1646 #define FREESPACE 50 /* Minimum freespace in blocks to permit transfer */
1647 #define FREENODES 5 /* Minimum number of inodes to permit transfer */
1659 struct statfs statfsb
;
1661 struct ustat ustatb
;
1664 if( stat(name
, &statb
) < 0 )
1667 if( (statb
.st_mode
|S_IFMT
) == S_IFREG
||
1668 (statb
.st_mode
|S_IFMT
) == S_IFEXT
||
1669 (statb
.st_mode
&S_IFMT
) == S_IF1EXT
)
1671 if( (statb
.st_mode
&S_IFMT
) == S_IFREG
)
1675 if( statfs(name
, &statfsb
)<0 )
1677 if( ustat(statb
.st_dev
, &ustatb
)<0 )
1682 * Use 512-byte blocks, because that's the unit "ustat" tends
1685 if( ((statfsb
.f_bavail
*statfsb
.f_bsize
)/512) < FREESPACE
)
1687 if( ustatb
.f_tfree
< FREESPACE
)
1690 logent("FREESPACE IS LOW","REMOTE TRANSFER DENIED - ");
1695 * The test for "> 0" is there because the @$%#@#@$ NFS
1696 * protocol doesn't pass the number of free files over the
1697 * wire, so "statfs" on an NFS file system always returns -1.
1699 if( statfsb
.f_ffree
> 0
1700 && statfsb
.f_ffree
< FREENODES
)
1702 if( ustatb
.f_tinode
< FREENODES
)
1705 logent("TOO FEW INODES","REMOTE TRANSFER DENIED - ");
1717 struct ustat
*ustat
;
1719 FILE *dfp
, *popen();
1720 char *fval
, buf
[BUFSIZ
];
1722 sprintf(buf
, "%s %d %d 2>&1", V7USTAT
, major(dev
), minor(dev
));
1723 if ((dfp
= popen(buf
, "r")) == NULL
)
1725 fval
= fgets(buf
, sizeof(buf
), dfp
);
1726 if (pclose(dfp
) != 0
1728 || sscanf(buf
, "%d %d", &ustat
->f_tfree
, &ustat
->f_tinode
) != 2)
1732 #endif /* V7USTAT */