1 /*-
2 * Copyright (c) 1985, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * %sccs.include.proprietary.c%
6 */
7
8 #ifndef lint
9 static char sccsid[] = "@(#)cntrl.c 8.1 (Berkeley) 06/06/93";
10 #endif /* not lint */
11
12 #include "uucp.h"
13 #include <sys/stat.h>
14 #include "uust.h"
15
16 extern int errno;
17 extern int turntime;
18 int willturn;
19 int HaveSentHup = 0;
20
21 struct Proto {
22 char P_id;
23 int (*P_turnon)();
24 int (*P_rdmsg)();
25 int (*P_wrmsg)();
26 int (*P_rddata)();
27 int (*P_wrdata)();
28 int (*P_turnoff)();
29 };
30
31 extern int gturnon(), gturnoff();
32 extern int grdmsg(), grddata();
33 extern int gwrmsg(), gwrdata();
34 extern int imsg(), omsg(), nullf();
35 #ifdef TCPIP
36 extern int twrmsg(), trdmsg();
37 extern int twrdata(), trddata();
38 #endif TCPIP
39 #ifdef PAD
40 extern int fturnon(), fturnoff();
41 extern int frdmsg(), frddata();
42 extern int fwrmsg(), fwrdata();
43 #endif PAD
44
45 struct Proto Ptbl[]={
46 #ifdef TCPIP
47 't', nullf, trdmsg, twrmsg, trddata, twrdata, nullf,
48 #endif TCPIP
49 #ifdef PAD
50 'f', fturnon, frdmsg, fwrmsg, frddata, fwrdata, fturnoff,
51 #endif PAD
52 'g', gturnon, grdmsg, gwrmsg, grddata, gwrdata, gturnoff,
53 '\0'
54 };
55
56 int (*Imsg)() = imsg, (*Omsg)() = omsg;
57
58 int (*Rdmsg)()=imsg, (*Rddata)();
59 int (*Wrmsg)()=omsg, (*Wrdata)();
60 int (*Turnon)()=nullf, (*Turnoff)() = nullf;
61
62 struct timeb Now, LastTurned, LastCheckedNoLogin;
63
64 static char *YES = "Y";
65 static char *NO = "N";
66
67 int TransferSucceeded = 1;
68
69 /* failure messages */
70 #define EM_MAX 6
71 #define EM_LOCACC "N1" /* local access to file denied */
72 #define EM_RMTACC "N2" /* remote access to file/path denied */
73 #define EM_BADUUCP "N3" /* a bad uucp command was generated */
74 #define EM_NOTMP "N4" /* remote error - can't create temp */
75 #define EM_RMTCP "N5" /* can't copy to remote directory - file in public */
76 #define EM_LOCCP "N6" /* can't copy on local system */
77
78 char *Em_msg[] = {
79 "COPY FAILED (reason not given by remote)",
80 "local access to file denied",
81 "remote access to path/file denied",
82 "system error - bad uucp command generated",
83 "remote system can't create temp file",
84 "can't copy to file/directory - file left in PUBDIR/user/file",
85 "can't copy to file/directory on local system - file left in PUBDIR/user/file"
86 };
87
88
89 #define XUUCP 'X' /* execute uucp (string) */
90 #define SLTPTCL 'P' /* select protocol (string) */
91 #define USEPTCL 'U' /* use protocol (character) */
92 #define RCVFILE 'R' /* receive file (string) */
93 #define SNDFILE 'S' /* send file (string) */
94 #define RQSTCMPT 'C' /* request complete (string - yes | no) */
95 #define HUP 'H' /* ready to hangup (string - yes | no) */
96 #define RESET 'X' /* reset line modes */
97
98 #define W_TYPE wrkvec[0]
99 #define W_FILE1 wrkvec[1]
100 #define W_FILE2 wrkvec[2]
101 #define W_USER wrkvec[3]
102 #define W_OPTNS wrkvec[4]
103 #define W_DFILE wrkvec[5]
104 #define W_MODE wrkvec[6]
105 #define W_NUSER wrkvec[7]
106
107 #define XFRRATE 35000L
108 #define RMESG(m, s, n) if (rmesg(m, s, n) != 0) {(*Turnoff)(); return FAIL;} else
109 #define RAMESG(s, n) if (rmesg('\0', s, n) != 0) {(*Turnoff)(); return FAIL;} else
110 #define WMESG(m, s) if(wmesg(m, s) != 0) {(*Turnoff)(); return FAIL;} else
111
112 char Wfile[MAXFULLNAME] = {'\0'};
113 char Dfile[MAXFULLNAME];
114
115 /*
116 * To avoid a huge backlog of X. files, start uuxqt every so often.
117 */
118 static int nXfiles = 0; /* number of X files since last uuxqt start */
119 static char send_or_receive;
120 struct stat stbuf;
121
122 /*
123 * cntrl - this routine will execute the conversation
124 * between the two machines after both programs are
125 * running.
126 *
127 * return codes
128 * SUCCESS - ok
129 * FAIL - failed
130 */
131
cntrl(role,wkpre)132 cntrl(role, wkpre)
133 int role;
134 char *wkpre;
135 {
136 char msg[BUFSIZ], rqstr[BUFSIZ];
137 register FILE *fp;
138 int filemode;
139 char filename[MAXFULLNAME], wrktype, *wrkvec[20];
140 extern (*Rdmsg)(), (*Wrmsg)();
141 extern char *index(), *lastpart();
142 int status = 1;
143 register int i, narg;
144 int mailopt, ntfyopt;
145 int ret;
146 static int pnum, tmpnum = 0;
147 extern int ReverseRole;
148
149 pnum = getpid();
150 Wfile[0] = '\0';
151 willturn = turntime > 0;
152 remaster:
153 #ifdef USG
154 time(&LastTurned.time);
155 LastTurned.millitm = 0;
156 #else !USG
157 ftime(&LastTurned);
158 #endif !USG
159 send_or_receive = RESET;
160 HaveSentHup = 0;
161 top:
162 for (i = 0; i < sizeof wrkvec / sizeof wrkvec[0]; i++)
163 wrkvec[i] = 0;
164 DEBUG(4, "*** TOP *** - role=%s\n", role ? "MASTER" : "SLAVE");
165 setproctitle("%s: %s", Rmtname, role ? "MASTER" : "SLAVE");
166 setupline(RESET);
167 if (Now.time > (LastCheckedNoLogin.time+60)) {
168 LastCheckedNoLogin = Now;
169 if (access(NOLOGIN, 0) == 0) {
170 logent(NOLOGIN, "UUCICO SHUTDOWN");
171 if (Debug > 4)
172 logent("DEBUGGING", "continuing anyway");
173 else {
174 WMESG(HUP, YES);
175 RMESG(HUP, msg, 1);
176 goto process;
177 }
178 }
179 }
180 if (role == MASTER) {
181 /* get work */
182 if (ReverseRole || (narg = gtwvec(Wfile, Spool, wkpre, wrkvec)) == 0) {
183 ReverseRole = 0;
184 WMESG(HUP, "");
185 RMESG(HUP, msg, 1);
186 goto process;
187 }
188 wrktype = W_TYPE[0];
189
190 msg[0] = '\0';
191 for (i = 1; i < narg; i++) {
192 strcat(msg, " ");
193 strcat(msg, wrkvec[i]);
194 }
195
196 if (wrktype == XUUCP) {
197 sprintf(rqstr, "X %s", msg);
198 logent(rqstr, "REQUEST");
199 goto sendmsg;
200 }
201 mailopt = index(W_OPTNS, 'm') != NULL;
202 ntfyopt = index(W_OPTNS, 'n') != NULL;
203
204 if (narg < 5 || W_TYPE[1] != '\0') {
205 char *bnp;
206 bnp = rindex(Wfile, '/');
207 sprintf(rqstr, "%s/%s", CORRUPT, bnp ? bnp + 1 : Wfile);
208 xmv(Wfile, rqstr);
209 syslog(LOG_WARNING, "%s CORRUPTED: %d args", Wfile,
210 narg);
211 Wfile[0] = '\0';
212 goto top;
213 }
214 sprintf(User, "%.9s", W_USER);
215 sprintf(rqstr, "(%s %s %s %s)", W_TYPE, W_FILE1,
216 W_FILE2, W_USER);
217 logent(rqstr, "REQUEST");
218 if (wrktype == SNDFILE ) {
219 strcpy(filename, W_FILE1);
220 i = expfile(filename);
221 DEBUG(4, "expfile type - %d, ", i);
222 if (i != 0 && chkpth(User, "", filename))
223 goto e_access;
224 strcpy(Dfile, W_DFILE);
225 fp = NULL;
226 if (index(W_OPTNS, 'c') == NULL) {
227 fp = fopen(subfile(Dfile), "r");
228 if (fp != NULL)
229 i = 0;
230 }
231 if (fp == NULL &&
232 (fp = fopen(subfile(filename), "r")) == NULL) {
233 /* can not read data file */
234 logent("CAN'T READ DATA", _FAILED);
235 TransferSucceeded = 1; /* else will keep sending */
236 USRF(USR_LOCACC);
237 unlinkdf(Dfile);
238 lnotify(User, filename, "can't access");
239 goto top;
240 }
241 /* if file exists but is not generally readable... */
242 if (i != 0 && fstat(fileno(fp), &stbuf) == 0
243 && (stbuf.st_mode & ANYREAD) == 0) {
244 e_access:;
245 /* access denied */
246 if (fp != NULL) {
247 fclose(fp);
248 fp = NULL;
249 }
250 TransferSucceeded = 1; /* else will keep sending */
251 logent("DENIED", "ACCESS");
252 USRF(USR_LOCACC);
253 unlinkdf(W_DFILE);
254 lnotify(User, filename, "access denied");
255 goto top;
256 }
257
258 setupline(SNDFILE);
259 }
260
261 if (wrktype == RCVFILE) {
262 strcpy(filename, W_FILE2);
263 expfile(filename);
264 if (chkpth(User, "", filename)
265 || chkperm(filename, index(W_OPTNS, 'd'))) {
266 /* access denied */
267 logent("DENIED", "ACCESS");
268 TransferSucceeded = 1; /* else will keep trying */
269 USRF(USR_LOCACC);
270 lnotify(User, filename, "access denied");
271 goto top;
272 }
273 sprintf(Dfile, "%s/TM.%05d.%03d", Spool, pnum, tmpnum++);
274 if ((fp = fopen(subfile(Dfile), "w")) == NULL) {
275 /* can not create temp */
276 logent("CAN'T CREATE TM", _FAILED);
277 USRF(USR_LNOTMP);
278 unlinkdf(Dfile);
279 goto top;
280 }
281 setupline(RCVFILE);
282 }
283 sendmsg:
284 DEBUG(4, "wrktype - %c\n", wrktype);
285 WMESG(wrktype, msg);
286 RMESG(wrktype, msg, 1);
287 goto process;
288 }
289
290 /* role is slave */
291 RAMESG(msg, 1);
292 if (willturn < 0)
293 willturn = msg[0] == HUP;
294
295 process:
296 DEBUG(4, "PROCESS: msg - %s\n", msg);
297 switch (msg[0]) {
298
299 case RQSTCMPT:
300 DEBUG(4, "RQSTCMPT:\n", CNULL);
301 if (msg[1] == 'N') {
302 i = atoi(&msg[2]);
303 if (i<0 || i>EM_MAX)
304 i = 0;
305 USRF( 1 << i );
306 logent(Em_msg[i], "REQUEST FAILED");
307 TransferSucceeded = 1; /* He had his chance */
308 }
309 if (msg[1] == 'Y') {
310 USRF(USR_COK);
311 TransferSucceeded = 1;
312 }
313 if (role == MASTER)
314 notify(mailopt, W_USER, W_FILE1, Rmtname, &msg[1]);
315
316 if (msg[2] == 'M' && role == MASTER) {
317 extern int Nfiles;
318 WMESG(HUP, "");
319 RMESG(HUP, msg, 1);
320 logent(Rmtname, "TURNAROUND");
321 #ifdef USG
322 time(&LastTurned.time);
323 LastTurned.millitm = 0;
324 #else !USG
325 ftime(&LastTurned);
326 #endif !USG
327 Nfiles = 0; /* force rescan of queue for work */
328 goto process;
329 }
330 goto top;
331
332 case HUP:
333 DEBUG(4, "HUP:\n", CNULL);
334 HaveSentHup = 1;
335 if (msg[1] == 'Y') {
336 if (role == MASTER)
337 WMESG(HUP, YES);
338 (*Turnoff)();
339 Rdmsg = Imsg;
340 Wrmsg = Omsg;
341 return SUCCESS;
342 }
343
344 if (msg[1] == 'N') {
345 if (role != MASTER) {
346 syslog(LOG_ERR, "Wrong Role - HUP");
347 cleanup(FAIL);
348 }
349 role = SLAVE;
350 goto remaster;
351 }
352
353 /* get work */
354 if (!iswrk(Wfile, "chk", Spool, wkpre)) {
355 WMESG(HUP, YES);
356 RMESG(HUP, msg, 1);
357 goto process;
358 }
359
360 WMESG(HUP, NO);
361 /*
362 * want to create an orphan uuxqt,
363 * so a double-fork is needed.
364 */
365 if (fork() == 0) {
366 xuuxqt();
367 _exit(0);
368 }
369 wait((int *)0);
370 role = MASTER;
371 goto remaster;
372
373 case XUUCP:
374 if (role == MASTER) {
375 goto top;
376 }
377
378 /* slave part */
379 i = getargs(msg, wrkvec, 20);
380 strcpy(filename, W_FILE1);
381 if (index(filename, ';') != NULL || index(W_FILE2, ';') != NULL
382 || i < 3) {
383 WMESG(XUUCP, NO);
384 goto top;
385 }
386 expfile(filename);
387 if (chkpth("", Rmtname, filename)) {
388 WMESG(XUUCP, NO);
389 logent("XUUCP DENIED", filename);
390 USRF(USR_XUUCP);
391 goto top;
392 }
393 sprintf(rqstr, "%s %s", filename, W_FILE2);
394 xuucp(rqstr);
395 WMESG(XUUCP, YES);
396 goto top;
397
398 case SNDFILE:
399 /* MASTER section of SNDFILE */
400
401 DEBUG(4, "%s\n", "SNDFILE:");
402 if (msg[1] == 'N') {
403 i = atoi(&msg[2]);
404 if (i < 0 || i > EM_MAX)
405 i = 0;
406 logent(Em_msg[i], "REQUEST FAILED");
407 USRF( 1 << i );
408 fclose(fp);
409 fp = NULL;
410 /* dont send him files he can't save */
411 if (strcmp(&msg[1], EM_NOTMP) == 0) {
412 WMESG(HUP, "");
413 RMESG(HUP, msg, 1);
414 goto process;
415 }
416 notify(mailopt, W_USER, W_FILE1, Rmtname, &msg[1]);
417 if (role != MASTER) {
418 syslog(LOG_ERR, "Wrong Role - SN");
419 cleanup(FAIL);
420 }
421 unlinkdf(W_DFILE);
422 goto top;
423 }
424
425 if (msg[1] == 'Y') {
426 /* send file */
427 if (role != MASTER) {
428 syslog(LOG_ERR, "Wrong Role - SY");
429 cleanup(FAIL);
430 }
431 if (fstat(fileno(fp), &stbuf) < 0) {
432 syslog(LOG_ERR, "stat(%s) failed: %m",filename);
433 cleanup(FAIL);
434 }
435 i = 1 + (int)(stbuf.st_size / XFRRATE);
436 if (send_or_receive != SNDFILE) {
437 send_or_receive = SNDFILE;
438 systat(Rmtname, SS_INPROGRESS, "SENDING");
439 }
440 ret = (*Wrdata)(fp, Ofn);
441 fclose(fp);
442 fp = NULL;
443 if (ret != SUCCESS) {
444 (*Turnoff)();
445 USRF(USR_CFAIL);
446 return FAIL;
447 }
448 RMESG(RQSTCMPT, msg, i);
449 unlinkdf(W_DFILE);
450 goto process;
451 }
452
453 /* SLAVE section of SNDFILE */
454 if (role != SLAVE) {
455 syslog(LOG_ERR, "Wrong Role - SLAVE");
456 cleanup(FAIL);
457 }
458
459 /* request to receive file */
460 /* check permissions */
461 i = getargs(msg, wrkvec, 20);
462 if (i < 5) {
463 char *bnp;
464 bnp = rindex(Wfile, '/');
465 sprintf(rqstr, "%s/%s", CORRUPT, bnp ? bnp + 1 : Wfile);
466 xmv(Wfile, rqstr);
467 syslog(LOG_WARNING, "%s CORRUPTED: %d args", Wfile, i);
468 Wfile[0] = '\0';
469 goto top;
470 }
471 sprintf(rqstr, "(%s %s %s %s)", W_TYPE, W_FILE1, W_FILE2,
472 W_USER);
473 logent(rqstr, "REQUESTED");
474 DEBUG(4, "msg - %s\n", msg);
475 strcpy(filename, W_FILE2);
476 /* Run uuxqt occasionally */
477 if (filename[0] == XQTPRE) {
478 if (++nXfiles > 10) {
479 nXfiles = 0;
480 /*
481 * want to create an orphan uuxqt,
482 * so a double-fork is needed.
483 */
484 if (fork() == 0) {
485 xuuxqt();
486 _exit(0);
487 }
488 wait((int *)0);
489 }
490 }
491 /* expand filename, i is set to 0 if this is
492 * is a vanilla spool file, so no stat(II)s are needed */
493 i = expfile(filename);
494 DEBUG(4, "expfile type - %d\n", i);
495 if (i != 0) {
496 if (chkpth("", Rmtname, filename)
497 || chkperm(filename, index(W_OPTNS, 'd'))) {
498 WMESG(SNDFILE, EM_RMTACC);
499 logent("DENIED", "PERMISSION");
500 goto top;
501 }
502 if (isdir(filename)) {
503 strcat(filename, "/");
504 strcat(filename, lastpart(W_FILE1));
505 }
506 }
507 sprintf(User, "%.9s", W_USER);
508
509 DEBUG(4, "chkpth ok Rmtname - %s\n", Rmtname);
510 /* speed things up by OKing file before
511 * creating TM file. If the TM file cannot be created,
512 * then the conversation bombs, but that seems reasonable,
513 * as there are probably serious problems then.
514 */
515 WMESG(SNDFILE, YES);
516 sprintf(Dfile, "%s/TM.%05d.%03d", Spool, pnum, tmpnum++);
517 if((fp = fopen(subfile(Dfile), "w")) == NULL) {
518 /* WMESG(SNDFILE, EM_NOTMP);*/
519 logent("CAN'T OPEN", "TM FILE");
520 unlinkdf(Dfile);
521 (*Turnoff)();
522 return FAIL;
523 }
524
525 if (send_or_receive != RCVFILE) {
526 send_or_receive = RCVFILE;
527 systat(Rmtname, SS_INPROGRESS, "RECEIVING");
528 }
529 ret = (*Rddata)(Ifn, fp);
530 fflush(fp);
531 if (ferror(fp) || fclose(fp))
532 ret = FAIL;
533
534 if (ret != SUCCESS) {
535 (void) unlinkdf(Dfile);
536 (*Turnoff)();
537 return FAIL;
538 }
539 /* copy to user directory */
540 ntfyopt = index(W_OPTNS, 'n') != NULL;
541 status = xmv(Dfile, filename);
542
543 if (willturn && Now.time > (LastTurned.time+turntime)
544 && iswrk(Wfile, "chk", Spool, wkpre)) {
545 WMESG(RQSTCMPT, status ? EM_RMTCP : "YM");
546 willturn = -1;
547 } else
548 WMESG(RQSTCMPT, status ? EM_RMTCP : YES);
549 if (i == 0)
550 ; /* vanilla file, nothing to do */
551 else if (status == 0) {
552 if (W_MODE == 0 || sscanf(W_MODE, "%o", &filemode) != 1)
553 filemode = BASEMODE;
554 chmod(subfile(filename), (filemode|BASEMODE)&0777);
555 arrived(ntfyopt, filename, W_NUSER, Rmtname, User);
556 } else {
557 logent(_FAILED, "COPY");
558 status = putinpub(filename, Dfile, W_USER);
559 DEBUG(4, "->PUBDIR %d\n", status);
560 if (status == 0)
561 arrived(ntfyopt, filename, W_NUSER, Rmtname, User);
562 }
563
564 goto top;
565
566 case RCVFILE:
567 /* MASTER section of RCVFILE */
568
569 DEBUG(4, "%s\n", "RCVFILE:");
570 if (msg[1] == 'N') {
571 i = atoi(&msg[2]);
572 if (i < 0 || i > EM_MAX)
573 i = 0;
574 logent(Em_msg[i], "REQUEST FAILED");
575 USRF( 1 << i );
576 fclose(fp);
577 fp = NULL;
578 notify(mailopt, W_USER, W_FILE1, Rmtname, &msg[1]);
579 if (role != MASTER) {
580 syslog(LOG_ERR, "Wrong Role - RN");
581 cleanup(FAIL);
582 }
583 unlinkdf(Dfile);
584 goto top;
585 }
586
587 if (msg[1] == 'Y') {
588 /* receive file */
589 if (role != MASTER) {
590 syslog(LOG_ERR, "Wrong Role - RY");
591 cleanup(FAIL);
592 }
593 if (send_or_receive != RCVFILE) {
594 send_or_receive = RCVFILE;
595 systat(Rmtname, SS_INPROGRESS, "RECEIVING");
596 }
597 ret = (*Rddata)(Ifn, fp);
598 fflush(fp);
599 if (ferror(fp) || fclose(fp))
600 ret = FAIL;
601 if (ret != SUCCESS) {
602 unlinkdf(Dfile);
603 (*Turnoff)();
604 USRF(USR_CFAIL);
605 return FAIL;
606 }
607 /* copy to user directory */
608 if (isdir(filename)) {
609 strcat(filename, "/");
610 strcat(filename, lastpart(W_FILE1));
611 }
612 status = xmv(Dfile, filename);
613 WMESG(RQSTCMPT, status ? EM_RMTCP : YES);
614 notify(mailopt, W_USER, filename, Rmtname,
615 status ? EM_LOCCP : YES);
616 if (status == 0) {
617 sscanf(&msg[2], "%o", &filemode);
618 if (filemode <= 0)
619 filemode = BASEMODE;
620 chmod(subfile(filename), (filemode|BASEMODE)&0777);
621 USRF(USR_COK);
622 } else {
623 logent(_FAILED, "COPY");
624 putinpub(filename, Dfile, W_USER);
625 USRF(USR_LOCCP);
626 }
627 if (msg[strlen(msg)-1] == 'M') {
628 extern int Nfiles;
629 WMESG(HUP, "");
630 RMESG(HUP, msg, 1);
631 logent(Rmtname, "TURNAROUND");
632 #ifdef USG
633 time(&LastTurned.time);
634 LastTurned.millitm = 0;
635 #else !USG
636 ftime(&LastTurned);
637 #endif !USG
638 Nfiles = 0; /* force rescan of queue for work */
639 goto process;
640 }
641 goto top;
642 }
643
644 /* SLAVE section of RCVFILE */
645 if (role != SLAVE) {
646 syslog(LOG_ERR, "Wrong Role - SLAVE RCV");
647 cleanup(FAIL);
648 }
649
650 /* request to send file */
651 sprintf(rqstr,"(%s)", msg);
652 logent(rqstr, "REQUESTED");
653
654 /* check permissions */
655 i = getargs(msg, wrkvec, 20);
656 if (i < 4) {
657 char *bnp;
658 bnp = rindex(Wfile, '/');
659 sprintf(rqstr, "%s/%s", CORRUPT, bnp ? bnp + 1 : Wfile);
660 xmv(Wfile, rqstr);
661 syslog(LOG_WARNING, "%s CORRUPTED: %d args", Wfile, i);
662 Wfile[0] = '\0';
663 goto top;
664 }
665 DEBUG(4, "msg - %s\n", msg);
666 DEBUG(4, "W_FILE1 - %s\n", W_FILE1);
667 strcpy(filename, W_FILE1);
668 expfile(filename);
669 if (isdir(filename)) {
670 strcat(filename, "/");
671 strcat(filename, lastpart(W_FILE2));
672 }
673 sprintf(User, "%.9s", W_USER);
674 if (chkpth("", Rmtname, filename) || anyread(filename)) {
675 WMESG(RCVFILE, EM_RMTACC);
676 logent("DENIED", "PERMISSION");
677 goto top;
678 }
679 DEBUG(4, "chkpth ok Rmtname - %s\n", Rmtname);
680
681 if ((fp = fopen(subfile(filename), "r")) == NULL) {
682 WMESG(RCVFILE, EM_RMTACC);
683 logent("CAN'T OPEN", "DENIED");
684 goto top;
685 }
686
687 /* ok to send file */
688 if (fstat(fileno(fp), &stbuf) < 0) {
689 syslog(LOG_ERR, "stat(%s) failed: %m", filename);
690 cleanup(FAIL);
691 }
692
693 i = 1 + (int)(stbuf.st_size / XFRRATE);
694 if (willturn && Now.time > (LastTurned.time+turntime)
695 && iswrk(Wfile, "chk", Spool, wkpre)) {
696 willturn = -1;
697 }
698 sprintf(msg, "%s %o%s", YES, (int)stbuf.st_mode & 0777,
699 willturn < 0 ? " M" : "");
700 WMESG(RCVFILE, msg);
701 if (send_or_receive != SNDFILE) {
702 send_or_receive = SNDFILE;
703 systat(Rmtname, SS_INPROGRESS, "SENDING");
704 }
705 ret = (*Wrdata)(fp, Ofn);
706 fclose(fp);
707 if (ret != SUCCESS) {
708 (*Turnoff)();
709 return FAIL;
710 }
711 RMESG(RQSTCMPT, msg, i);
712 goto process;
713 }
714 (*Turnoff)();
715 return FAIL;
716 }
717
718
719 /*
720 * read message 'c'. try 'n' times
721 *
722 * return code: SUCCESS | FAIL
723 */
rmesg(c,msg,n)724 rmesg(c, msg, n)
725 register char *msg, c;
726 register int n;
727 {
728 char str[MAXFULLNAME];
729
730 DEBUG(4, "rmesg - '%c' ", c);
731 while ((*Rdmsg)(msg, Ifn) != SUCCESS) {
732 if (--n > 0) {
733 sprintf(str, "%d", n);
734 logent(str, "PATIENCE");
735 continue;
736 }
737 DEBUG(4, "got FAIL\n", CNULL);
738 if (c != '\0')
739 sprintf(str, "expected '%c' got FAIL (%d)", c, errno);
740 else
741 sprintf(str, "expected ANY got FAIL (%d)", errno);
742 logent(str, "BAD READ");
743 return FAIL;
744 }
745 if (c != '\0' && msg[0] != c) {
746 DEBUG(4, "got %s\n", msg);
747 sprintf(str, "expected '%c' got %s", c, msg);
748 logent(str, "BAD READ");
749 return FAIL;
750 }
751 DEBUG(4, "got %s\n", msg);
752 return SUCCESS;
753 }
754
755
756 /*
757 * write a message (type m)
758 *
759 * return codes: SUCCESS - ok | FAIL - ng
760 */
wmesg(m,s)761 wmesg(m, s)
762 register char *s, m;
763 {
764 DEBUG(4, "wmesg '%c' ", m);
765 DEBUG(4, "%s\n", s);
766 return (*Wrmsg)(m, s, Ofn);
767 }
768
769 /*
770 * mail results of command
771 *
772 * return codes: none
773 */
notify(mailopt,user,file,sys,msgcode)774 notify(mailopt, user, file, sys, msgcode)
775 char *user, *file, *sys, *msgcode;
776 {
777 char str[BUFSIZ];
778 int i;
779 char *msg;
780
781 if (!mailopt && *msgcode == 'Y')
782 return;
783 if (*msgcode == 'Y')
784 msg = "copy succeeded";
785 else {
786 i = atoi(msgcode + 1);
787 if (i < 1 || i > EM_MAX)
788 i = 0;
789 msg = Em_msg[i];
790 }
791 sprintf(str, "file %s!%s -- %s\n",
792 sys,file, msg);
793 mailst(user, str, CNULL);
794 return;
795 }
796
797 /*
798 * local notify
799 *
800 * return code - none
801 */
lnotify(user,file,mesg)802 lnotify(user, file, mesg)
803 char *user, *file, *mesg;
804 {
805 char mbuf[200];
806 sprintf(mbuf, "file %s!%s -- %s\n", Myname, file, mesg);
807 mailst(user, mbuf, CNULL);
808 return;
809 }
810
811 char UsingProtocol;
812
813 /*
814 * converse with the remote machine, agree upon a protocol (if possible)
815 * and start the protocol.
816 *
817 * return codes:
818 * SUCCESS - successful protocol selection
819 * FAIL - can't find common or open failed
820 */
startup(role)821 startup(role)
822 int role;
823 {
824 extern (*Rdmsg)(), (*Wrmsg)();
825 extern char *blptcl(), fptcl();
826 char msg[BUFSIZ], str[MAXFULLNAME];
827
828 Rdmsg = Imsg;
829 Wrmsg = Omsg;
830 if (role == MASTER) {
831 RMESG(SLTPTCL, msg, 1);
832 if ((str[0] = fptcl(&msg[1])) == NULL) {
833 /* no protocol match */
834 WMESG(USEPTCL, NO);
835 return FAIL;
836 }
837 str[1] = '\0';
838 WMESG(USEPTCL, str);
839 if (stptcl(str) != 0)
840 return FAIL;
841 DEBUG(4, "protocol %s\n", str);
842 UsingProtocol = str[0];
843 return SUCCESS;
844 }
845 else {
846 WMESG(SLTPTCL, blptcl(str));
847 RMESG(USEPTCL, msg, 1);
848 if (msg[1] == 'N') {
849 return FAIL;
850 }
851
852 if (stptcl(&msg[1]) != 0)
853 return FAIL;
854 DEBUG(4, "Protocol %s\n", msg);
855 UsingProtocol = msg[1];
856 return SUCCESS;
857 }
858 }
859
860 /*
861 * choose a protocol from the input string (str) and return the it
862 *
863 * return codes:
864 * '\0' - no acceptable protocol
865 * any character - the chosen protocol
866 */
867 char
fptcl(str)868 fptcl(str)
869 register char *str;
870 {
871 register struct Proto *p;
872 extern char LineType[];
873
874 for (p = Ptbl; p->P_id != '\0'; p++) {
875 #ifdef TCPIP
876 /* Only use 't' on TCP/IP */
877 if (p->P_id == 't' && strcmp("TCP", LineType))
878 continue;
879 #endif TCPIP
880 #ifdef PAD
881 /* only use 'f' protocol on PAD */
882 if (p->P_id == 'f' && strcmp("PAD", LineType))
883 continue;
884 #endif PAD
885 if (index(str, p->P_id) != NULL) {
886 return p->P_id;
887 }
888 }
889
890 return '\0';
891 }
892
893 /*
894 * build a string of the letters of the available protocols
895 */
896 char *
blptcl(str)897 blptcl(str)
898 register char *str;
899 {
900 register struct Proto *p;
901 register char *s;
902
903 for (p = Ptbl, s = str; (*s++ = p->P_id) != '\0'; p++)
904 ;
905 *s = '\0';
906 return str;
907 }
908
909 /*
910 * this routine will set up the six routines
911 * (Rdmsg, Wrmsg, Rddata, Wrdata, Turnon, Turnoff) for the
912 * desired protocol.
913 *
914 * return codes:
915 * SUCCESS - ok
916 * FAIL - no find or failed to open
917 *
918 */
stptcl(c)919 stptcl(c)
920 register char *c;
921 {
922 register struct Proto *p;
923
924 for (p = Ptbl; p->P_id != '\0'; p++) {
925 if (*c == p->P_id) {
926 /* found protocol - set routines */
927 Rdmsg = p->P_rdmsg;
928 Wrmsg = p->P_wrmsg;
929 Rddata = p->P_rddata;
930 Wrdata = p->P_wrdata;
931 Turnon = p->P_turnon;
932 Turnoff = p->P_turnoff;
933 if ((*Turnon)() != SUCCESS)
934 return FAIL;
935 DEBUG(4, "Proto started %c\n", *c);
936 return SUCCESS;
937 }
938 }
939 DEBUG(4, "Proto start-fail %c\n", *c);
940 return FAIL;
941 }
942
943 /*
944 * put file in public place. if successful, filename is modified
945 *
946 * return code SUCCESS | FAIL
947 */
948
putinpub(file,tmp,user)949 putinpub(file, tmp, user)
950 register char *file, *tmp, *user;
951 {
952 char fullname[MAXFULLNAME];
953 char *lastpart();
954 int status;
955
956 sprintf(fullname, "%s/%s/", PUBDIR, user);
957 if (mkdirs(fullname) != 0) {
958 /* can not make directories */
959 DEBUG(1, "Cannot mkdirs(%s)\n", fullname);
960 return FAIL;
961 }
962 strcat(fullname, lastpart(file));
963 status = xmv(tmp, fullname);
964 if (status == 0) {
965 strcpy(file, fullname);
966 chmod(subfile(fullname), BASEMODE);
967 }
968 return status;
969 }
970
971 /*
972 * unlink D. file
973 *
974 * return code - none
975 */
976
unlinkdf(file)977 unlinkdf(file)
978 register char *file;
979 {
980 if (strlen(file) > 6)
981 unlink(subfile(file));
982 return;
983 }
984
985 /*
986 * notify receiver of arrived file
987 *
988 * return code - none
989 */
arrived(opt,file,nuser,rmtsys,rmtuser)990 arrived(opt, file, nuser, rmtsys, rmtuser)
991 char *file, *nuser, *rmtsys, *rmtuser;
992 {
993 char mbuf[200];
994
995 if (!opt)
996 return;
997 sprintf(mbuf, "%s from %s!%s arrived\n", file, rmtsys, rmtuser);
998 mailst(nuser, mbuf, CNULL);
999 return;
1000 }
1001
nullf()1002 nullf()
1003 {
1004 return SUCCESS;
1005 }
1006