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