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
Pname(fileid,dfile,direct)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
cntrl()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
rmesg(c,msg)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
wmesg(m,s)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
notify(mailopt,user,msgin,sys,msgcode)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
lnotify(user,msgin,mesg)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
stmesg(f,m)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
startup(void)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
fptcl(str,valid)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
blptcl(str)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
stptcl(c)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
unlinkdf(file)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
arrived(opt,file,nuser,rmtsys,rmtuser)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
nospace(name)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
ustat(dev,ustat)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