|
|
1.1 root 1: /*
2: * dcpxfer.c
3: *
4: * Revised edition of dcp
5: *
6: * Stuart Lynne May/87
7: *
8: * Copyright (c) Richard H. Lamb 1985, 1986, 1987 Changes Copyright (c) Stuart
9: * Lynne 1987
10: *
11: * "DCP" a uucp clone. Copyright Richard H. Lamb 1985,1986,1987
12: * file send routines
13: */
14:
15: #include "dcp.h"
16: #include <signal.h>
17: #include <ctype.h>
18: #include <sys/timeb.h>
19: #include <sys/stat.h>
20: #include <access.h>
21: #include "perm.h"
22:
23: extern int (*getpkt)(), (*sendpkt)(), (*openpk)(), (*closepk)();
24:
25: extern int errno;
26: extern char *sys_errlist[];
27: extern char *strtok();
28: extern char *rebuildfn();
29: static char tempname[] = "/usr/spool/uucp/TM.XXXXXX";
30: static unsigned char rpacket[MAXPACK];
31: static unsigned char spacket[MAXPACK];
32: char reason [80];
33: static char S_record [BUFSIZ];
34: static int lstat;
35: extern int canwrite();
36: #define BIGBUFSZ (BUFSIZ * 20)
37: static char bigreadbuf [BIGBUFSZ];
38:
39: struct timeb transferstart; /* transfer start time */
40: struct timeb transferstop; /* transfer stop time */
41:
42: /*
43: * s d a t a
44: *
45: * Send File Data
46: */
47: sdata()
48: {
49: for (;;) {
50: if ((size = read(fpfd, spacket, pktsize)) <= 0) /* Get data */
51: return 'Z'; /* If EOF set state to that */
52: bytecount += size;
53: if ((*sendpkt) (spacket, size, 0))
54: return cantsend(); /* send data */
55: }
56: }
57:
58: /*
59: * s b r e a k
60: *
61: */
62: sbreak()
63: {
64: if (sendmsg("H") < 0)
65: return cantsend();
66: if (getmsg(spacket) < 0) {
67: plog(M_CONVERSE, "Cannot get reply to H (sbreak)");
68: terminatelevel++;
69: return 'Y'; /* was return 0 */
70: }
71: printmsg(M_CONVERSE, "Switch modes: %s", spacket);
72: if (spacket[1] == 'N')
73: return 'G';
74: return 'Y';
75: }
76:
77: /*
78: * s e o f
79: *
80: * Send End-Of-File.
81: */
82: seof()
83: {
84: double elapsed;
85:
86: close(fpfd);
87: fpfd = -1;
88: printmsg(M_TRANSFER, "seof");
89: if ((*sendpkt) (spacket, 0, 0) < 0)
90: return cantsend(); /* length zero packet indicates EOF */
91: if (getmsg(spacket) < 0)
92: return cantread(); /* was plog; termlev++, no ret*/
93: printmsg(M_TRANSFER, "seof: spacket is %s.", spacket);
94: if (strncmp(spacket, "CY", 2) != 0) {
95: sprintf(reason, "Remote would not accept file %s", fromfilep);
96: plog(M_TRANSFER, reason);
97: notifystatus(fromfilep, tofilep, 1, 0, lstat);
98: return 'F';
99: }
100: if (lstat && (index(optionp, 'c') == NULL)) {
101: unlink(xfromfile);
102: /* plog("unlinking %s", xfromfile); */
103: printmsg(M_TRANSFER, "unlinking %s.", xfromfile);
104: }
105: printmsg(M_TRANSFER, "seof: Transfer of %s completed.",
106: fromfilep);
107: ftime(&transferstop);
108: printmsg(M_TRANSFER, "Stop time is %ld.%03d\n",
109: transferstop.time, transferstop.millitm);
110: elapsed =
111: (double)transferstop.time - (double)transferstart.time;
112: elapsed +=
113: ((double)transferstop.millitm -
114: (double)transferstart.millitm) / 1000.0;
115: if (total_errors > 0)
116: plog(M_TRANSFER,
117: "S (OK) %ld bytes, %5.2f seconds, %5.1f Bps, %d error%c",
118: bytecount, elapsed, (double) bytecount / elapsed,
119: total_errors, total_errors == 1 ? ' ' : 's');
120: else
121: plog(M_TRANSFER, "S (OK) %ld bytes, %5.2f seconds, %5.1f Bps",
122: bytecount, elapsed, (double) bytecount / elapsed);
123: notifystatus(fromfilep, tofilep, 1, 1, lstat);
124: return 'F'; /* go get the next file to send */
125: }
126:
127: /*
128: * s f i l e
129: *
130: * Send File Header.
131: * This needs to respond to:
132: * 1) commands from a C. file
133: * 2) requests from remote.
134: */
135: sfile()
136: {
137: printmsg(M_SPOOL, "Sending %s as %s,\n\tspool %s",
138: fromfilep, tofilep, xfromfile);
139: plog(M_SPOOL, "S (%s)->(%s)", fromfilep, tofilep);
140: bytecount = 0;
141: total_errors = 0;
142: ftime(&transferstart);
143: printmsg(M_TRANSFER, "Start time is %ld.%03d\n",
144: transferstart.time, transferstart.millitm);
145: return 'D';
146: }
147:
148: /*
149: * s i n i t
150: *
151: * Send Initiate: send this host's parameters and get other side's back.
152: */
153: sinit()
154: {
155: if ((*openpk) ())
156: return 'A';
157: return ('B');
158: }
159:
160: /*
161: * cdotcmd
162: * read commands from C. file, and dispatch accordingly.
163: * This routine and the corresponding routine rmtcmd need to set up
164: * the following global variables.
165: * fromfilep pointer to file name that is source.
166: * tofilep pointer to file name that is destination.
167: * xfromfile file name that is actual source, eg, spool file.
168: * optionp pointer to option string.
169: * modep pointer to octal mode string.
170: * notifyp pointer to user to be notified
171: * These control the action of sendf, sfile and seof.
172: *
173: */
174: cdotcmd()
175: {
176: char *cp;
177:
178: lstat = 1;
179: printmsg(M_SPOOL, "cdotcmd enter");
180: if (fpfd != -1) { /* If not already open, */
181: plog(M_SPOOL, "File already open");
182: terminatelevel++;
183: return 'A'; /* If something's already open, we' trouble */
184: }
185: printmsg(M_SPOOL, "looking for next file...");
186: if (getcline()) { /* get next file from current work */
187: fclose(cfp);
188: printmsg(M_SPOOL, "unlinking %s", cfile);
189: unlink(cfile); /* close and delete completed workfile */
190: cfp = NULL;
191: return 'B'; /* end controlling session */
192: }
193: if (*clinep [1] == 'R') { /* ask for file */
194: int permerr = 0;
195: printmsg(M_SPOOL, "getcline gave us an 'R' rec");
196: if ((cp = rebuildfn(tofilep)) == NULL) {
197: sprintf(reason, "No such user as referenced in \"%s\"",
198: tofilep);
199: permerr = 1;
200: } else
201: strcpy(xtofile, cp);
202: if (!permerr && !perm_write(xtofile)) {
203: sprintf(reason, "No permission to write file \"%s\"",
204: xtofile);
205: permerr = 1;
206: }
207: if (!permerr && !canwrite(xtofile)) {
208: sprintf(reason, "Unable to create \"%s\"; %s",
209: xtofile, sys_errlist[errno]);
210: permerr = 1;
211: }
212: if (permerr) {
213: plog(M_SPOOL, reason);
214: notifystatus(fromfilep, xtofile, 0, 0, lstat);
215: return 'F'; /* Give up if can't */
216: }
217: if (sendmsg(S_record) < 0) /* really S&R_record */
218: return cantsend();
219: if (getmsg(spacket) < 0)
220: return cantread();
221: printmsg(M_SPOOL, "spacket is %s", spacket);
222: if ((spacket [0] != 'R') || (spacket [1] != 'Y')) {
223: sprintf(reason, "Remote won't send file \"%s\".",
224: fromfilep);
225: plog(M_SPOOL, reason);
226: notifystatus(fromfilep, xtofile, 0, 0, lstat);
227: return 'F'; /* was return 'A' */
228: }
229: return rfile();
230: }
231: if (strcmp(clinep [1], "S") == 0) {
232: int noperm;
233: noperm = 0;
234: printmsg(M_SPOOL, "Opening \"%s\" for sending.", xfromfile);
235: if ((strcmp(perm_value(sendfiles_e), "call") == 0) ||
236: !perm_read(xfromfile)) {
237: if (role != MASTER) {
238: sprintf(reason,
239: "No permission to send as remote \"%s\"",
240: xfromfile);
241: noperm = 1;
242: }
243: } else if ((strcmp(perm_value(sendfiles_e), "yes") != 0) ||
244: !perm_read(xfromfile)) {
245: sprintf(reason,"No permission to send file\"%s\"",
246: xfromfile);
247: noperm = 1;
248: }
249: if (noperm) {
250: plog(M_TRANSFER, reason);
251: notifystatus(xfromfile, xtofile, 0, 0, lstat);
252: return 'F';
253: }
254: fpfd = open(xfromfile, 0); /* open the file to be sent */
255: if (fpfd == -1) {
256: sprintf(reason, "Unable to read \"%s\"; %s",
257: xfromfile, sys_errlist[errno]);
258: plog(M_TRANSFER, reason);
259: notifystatus(xfromfile, xtofile, 0, 0, lstat);
260: return 'F';
261: }
262: /* send 'S fromfile tofile user - tofile <perms>'. */
263: if (sendmsg(S_record) < 0)
264: return cantsend(); /* was return 0 */
265: if (getmsg(spacket) < 0)
266: return cantread(); /* was return 0 */
267: printmsg(M_SPOOL, "spacket is %s", spacket);
268: if (spacket[1] != 'Y') {
269: sprintf(reason, "Remote won't accept file \"%s\"",
270: xfromfile);
271: plog(M_TRANSFER, reason);
272: notifystatus(xfromfile, xtofile, 1, 0, lstat);
273: close(fpfd);
274: fpfd = -1;
275: return 'F';
276: }
277: return sfile();
278: }
279: plog(M_SPOOL, "unknown record in \"%s\" of \"%s\"", cfile, clinep[1]);
280: return 'Y';
281: }
282:
283: /*
284: * getcline()
285: * get one line from the C. file and split it apart.
286: */
287: getcline()
288: {
289: char *p;
290: static char line[BUFSIZ];
291: if (fgets(line, BUFSIZ, cfp) == (char *) NULL)
292: return 1;
293: if ((p = index(line, '\n')) != NULL)
294: *p = '\0';
295: strcpy(cline, line);
296: return sepcline();
297:
298: }
299:
300: sepcline()
301: {
302: char *sp;
303: int i;
304:
305: printmsg(M_SPOOL, "sepcline: line is %s", cline);
306: strcpy(S_record, cline);
307: sp = cline;
308: for (i=0; i<10; i++)
309: clinep[i] = NULL;
310: for (i=1; i<10; i++) {
311: if ( (clinep[i]=strtok(sp, " \t\n")) == NULL ){
312: break;
313: }
314: printmsg(M_SPOOL, "cline[%d]:\t%\"%s\"", i, clinep[i]);
315: sp = NULL;
316: }
317:
318: printmsg(M_SPOOL,"PERMISSIONS WATCH: cline[%d] is %o",i, clinep[i]);
319:
320: /* If the last field of a parsed command line is NOT null, then
321: * there is something wrong with the line parsed. Leave a message
322: * to this affect in the logs, and print the offending line there
323: * as well. Abort processing this file.
324:
325: * It has not yet been determined what affects this will have.
326: * It may keep other requests from the site which is expecting to
327: * receive files from receving all of the files it expects.
328:
329: * the following is a short description of how this was called:
330:
331: sendf() -> calls cdotcmd() until 'complete' (dcp.c)
332: cdotcmd() -> calls getcline() until a non-zero
333: value is returned. When a non zero
334: value is returned, the C. file being
335: read is closed and deleted. A 'B' is
336: then returned back to sendf()
337: getcline() -> calls sepcline (breaks out the C. fields)
338:
339: * Bob Hemedinger 01/27/92
340: */
341:
342: /* 01/30/92: removed the return statement. We WANT to continue
343: * if we don't see the NULL terminator for compatibility with
344: * other variants.
345: */
346:
347: if (clinep[9] != NULL) {
348: plog(M_SPOOL, "Error parsing command 'C.' file");
349: plog(M_SPOOL, "last sepcline field not null");
350: plog(M_SPOOL, "Actually parsed: ");
351: plog(M_SPOOL, " %s %s %s %s %s %s %s %s %s",
352: clinep[1], clinep[2], clinep[3],
353: clinep[4], clinep[5], clinep[6],
354: clinep[7], clinep[8], clinep[9]);
355: }
356: nclinep = i;
357: fromfilep = clinep[2];
358: tofilep = clinep[3];
359: usernamep = clinep[4];
360: optionp = clinep[5];
361: spoolfilep = clinep[6];
362: modep = clinep[7];
363: notifyp = clinep[8];
364:
365: if (strcmp(clinep[1], "S") == 0) {
366: sprintf(xfromfile, "%s/%s/%s", SPOOLDIR, rmtname, spoolfilep);
367: if (index(optionp, 'c') != NULL) /* this looks weak */
368: strcpy(xfromfile, fromfilep);
369: } else if (strcmp(clinep[1], "R") == 0) {
370: strcpy(xfromfile, fromfilep);
371: } else if (*clinep[1] == 'H') {
372: ;
373: } else {
374: plog(M_SPOOL, "Unrecog record type %s", cline);
375: printmsg(M_SPOOL, "Unrecog type %s %s %s", cline[1],
376: cline[2], cline[3]);
377: return 1;
378: }
379: return 0;
380: }
381:
382: /*********************** MISC SUB SUB PROTOCOL *************************/
383:
384: /*
385: *
386: * schkdir
387: * scan the dir
388: */
389: schkdir()
390: {
391: char c;
392:
393: c = scandir();
394:
395: if (c == 'Q') {
396: return ('Y');
397: }
398: if (c == 'S') {
399: sprintf(rpacket, "HN");
400: if ((*sendpkt) (rpacket, 0, 1))
401: return cantsend();
402: }
403: return ('B');
404: }
405:
406: /*
407: * endp() end protocol
408: *
409: */
410: endp()
411: {
412:
413: (void) sendmsg("HY");
414: (*closepk) ();
415: return 'P';
416: }
417:
418:
419:
420: /***********************RECEIVE PROTOCOL**********************/
421:
422: /*
423: * r d a t a
424: *
425: * Receive Data
426: */
427: rdata()
428: {
429: int len;
430:
431: if ((*getpkt) (rpacket, &len))
432: return cantread();
433: if (len == 0)
434: return reof();
435: if (write(fpfd, rpacket, len) != len) /* Write the data to the file */
436: return 'Y';
437: bytecount += len;
438: return 'J'; /* Remain in data state */
439: /* changed to J */
440: }
441:
442: /*
443: * reof
444: * handle eof on read.
445: * try to link the temp file to the new name;
446: * if not successful, then copy it.
447: */
448: reof()
449: {
450: int tfpfd;
451: int noperm;
452: double elapsed;
453: int mode;
454: int bytes;
455:
456: noperm = 0;
457: tfpfd = -1;
458: close(fpfd);
459: fpfd = -1;
460: unlink(xtofile);
461: if (link(tempname, xtofile) == -1) {
462: if ((tfpfd = open(tempname, 0)) == -1) {
463: sprintf(reason, "Unable to reread \"%s\"; %s",
464: tempname, sys_errlist[errno]);
465: noperm = 1;
466: } else if ((fpfd = creat(xtofile, 0644)) == -1) {
467: sprintf(reason, "Unable to create \"%s\"; %s (rdata)",
468: xtofile, sys_errlist[errno]);
469: noperm = 1;
470: }
471: if (noperm) {
472: plog(M_TRANSFER, reason);
473: notifystatus(fromfilep, tempname, 0, 0, lstat);
474: if (sendmsg("CN") < 0) {
475: plog(M_SPOOL, "Message CN refused");
476: return cantsend();
477: }
478: if (tfpfd != -1)
479: close(tfpfd);
480: if (fpfd != -1)
481: close(fpfd);
482: return 'F';
483: }
484: while ((bytes = read(tfpfd, bigreadbuf, BIGBUFSZ)) > 0)
485: write(fpfd, bigreadbuf, bytes);
486: close(tfpfd);
487: close(fpfd);
488: fpfd = -1;
489: }
490: unlink(tempname);
491:
492: /* this problem showed up in 4.0. When we request a file, nothing specifies
493: the file permissions. This little ditty will take care of the problem.
494: Now we check the value of nclinep, as it holds the place where we
495: exitted the loop which parses the command received. If we broke out at 7,
496: which is where the file permissions are stored, then we end up with garbage
497: permissions in modep (which is clinep[7]). For these cases, we will default
498: to permissions of 0644 and pray that the customers can live with it.
499:
500: Bob H. 08/26/92 */
501:
502: if ((strlen(modep) > 0) && (mode = getoct(modep)) != 0 &&
503: (chmod(xtofile, (nclinep == 7 ? 0644:getoct(modep)) ) == -1)) {
504: printmsg(M_TRANSFER, "Unable to change permission");
505: plog(M_TRANSFER,
506: "Unable to change permission to \"%s\" on file \"%s\"",
507: modep, xtofile);
508: }
509: /* now, do the copy. rewind the above file and reread it */
510: /* we ought to do the copy in a temp file, and move it here */
511: printmsg(M_TRANSFER, "transfer complete");
512: ftime(&transferstop);
513: printmsg(M_TRANSFER, "Stop time is %ld.%03d\n",
514: transferstop.time, transferstop.millitm);
515: elapsed =
516: (double)transferstop.time -
517: (double)transferstart.time;
518: elapsed +=
519: ((double)transferstop.millitm -
520: (double)transferstart.millitm) / 1000.0;
521: if (total_errors > 0)
522: plog(M_TRANSFER,
523: "R (OK) %ld bytes, %5.2f seconds, %5.1f Bps, %d error%c",
524: bytecount, (double)elapsed, bytecount / elapsed,
525: total_errors, total_errors == 1 ? ' ' : 's');
526: else
527: plog(M_TRANSFER, "R (OK) %ld bytes, %5.2f seconds, %5.1f Bps",
528: bytecount, (double)elapsed, bytecount / elapsed);
529: notifystatus(fromfilep, xtofile, 0, 1, lstat);
530: printmsg(M_TRANSFER, "returning from rdata");
531: if (sendmsg("CY") < 0) {
532: strcpy(reason, "Message CY refused.");
533: plog(M_TRANSFER, reason);
534: return cantsend();
535: }
536: return 'F';
537: }
538:
539: /*
540: * Analog of cdotcmd. This takes 'S' records or 'R' records
541: * from the other end and dispatches them properly.
542: */
543: rmtcmd()
544: {
545: static char buf[256];
546: char *cp;
547: int noperm;
548:
549: lstat = 0;
550: if (getmsg(buf) < 0) {
551: printmsg(M_LOWPROTO, "in rmtcmd, getmsg says -1");
552: return cantread(); /* was return 0 */
553: }
554: printmsg(M_TRANSFER, "buf[0] is %c", buf[0]);
555: strcpy(cline, buf);
556: sepcline();
557: if (*clinep [1] == 'H') { /* used to be buf [0] */
558: printmsg(M_TRANSFER, "rmtcmd got H, returning C");
559: return 'C';
560: }
561: printmsg(M_TRANSFER, "rmtcmd: buf %d \"%s\"", strlen(S_record),
562: S_record);
563: if (strcmp (clinep [1], "R") == 0) {
564: printmsg(M_INFO, "rmdcmd: send file R");
565: printmsg(M_SPOOL, "Opening %s for sending.", xfromfile);
566: if ((strcmp(perm_value(request_e), "yes") != 0) ||
567: !perm_read(xfromfile)) {
568: sprintf(reason, "Request permission denied: \"%s\"",
569: xfromfile);
570: plog(M_TRANSFER, reason);
571: sendmsg("RN");
572: notifystatus(fromfilep, xtofile, 0, 0, lstat);
573: return 'F';
574: } else {
575: fpfd = open(xfromfile, 0);
576: /* open the file to be sent */
577: if (fpfd == -1) { /* If bad file pointer, give up */
578: sprintf(reason,
579: "Cannot open file \"%s\".", xfromfile);
580: plog(M_TRANSFER, reason);
581: sendmsg("RN");
582: notifystatus(fromfilep, xtofile, 0, 0, lstat);
583: return 'F'; /* was return 'A' */
584: }
585: sendmsg("RY");
586: return sfile();
587: }
588: }
589: printmsg(M_INFO, "rmtcmd: receive file \"%s\"", tofilep);
590: if ((cp = index(optionp, 'c')) != NULL) /* oops, not allowd*/
591: *cp = ' ';
592: noperm = 0;
593: if ((cp = rebuildfn(tofilep)) == NULL) {
594: noperm = 1;
595: sprintf(reason, "No such user as referenced in \"%s\"",
596: tofilep);
597: } else
598: strcpy(xtofile, rebuildfn(tofilep));
599: if (!noperm && !perm_write(xtofile)) {
600: sprintf(reason, "No permission to write file \"%s\"", xtofile);
601: noperm = 1;
602: }
603: if (!noperm && !canwrite(xtofile)) {
604: sprintf(reason, "rmtcmd: Unable to create file \"%s\": %s",
605: xtofile, sys_errlist[errno]);
606: noperm = 1;
607: }
608: if (noperm) {
609: plog(M_TRANSFER, reason);
610: notifystatus(fromfilep, xtofile, 0, 0, lstat);
611: if (sendmsg("SN") < 0)
612: return cantsend();
613: return 'F';
614: }
615: if (sendmsg("SY") < 0) {
616: plog(M_TRANSFER, "Can't send SY");
617: return 'Y';
618: }
619: return rfile();
620: }
621:
622: /*
623: * r f i l e
624: *
625: * Receive File Header
626: */
627: rfile()
628: {
629: printmsg(M_TRANSFER, "Receiving %s as %s", fromfilep, xtofile);
630: /* create temp file name, open it for output */
631: if ((fpfd = creat(mktemp(tempname), 0644)) == -1) {
632: sprintf(reason, "Unable to create \"%s\"; %s",
633: tempname, sys_errlist[errno]);
634: plog(M_TRANSFER, reason);
635: notifystatus(fromfilep, xtofile, 0, 0, lstat);
636: return 'F'; /* Give up if can't */
637: }
638: plog(M_TRANSFER, "R (%s)<-(%s)", xtofile, fromfilep);
639: bytecount = 0;
640: total_errors = 0;
641: ftime(&transferstart);
642: printmsg(M_TRANSFER, "Start time is %ld.%03d\n",
643: transferstart.time, transferstart.millitm);
644: return 'J'; /* Switch to data state */
645: }
646:
647: /*
648: * r i n i t
649: *
650: * Receive Initialization
651: */
652: rinit()
653: {
654: if ((*openpk) ()) {
655: plog(M_TRANSFER, "Unable to get opening packet");
656: return 'Y';
657: }
658: return ('F');
659: }
660:
661: /*
662: * |getmsg()| recieves a null-terminated "conversation-level" message
663: * from the communications channel. This may require one or more packets,
664: * but all of them will be "long-data" packets containing a full 64 bytes.
665: */
666: int getmsg(dest)
667: char *dest;
668: {
669: int len;
670:
671: while(1) {
672: if ((*getpkt)(dest, &len) < 0)
673: return(-1);
674: *(dest + len) = '\0'; /* make sure it's terminated */
675: if (strlen(dest) != len)
676: break; /* we reached the terminator */
677: dest += len;
678: }
679: return( 0 );
680: }
681:
682: /*
683: * |sendmsg(message)| sends a null-terminated "conversation-level" message.
684: */
685: int sendmsg(message)
686: char *message;
687: {
688: int len;
689: len = strlen(message) + 1; /* total length including '\0' */
690:
691: while(1) {
692: if ((*sendpkt)(message, 0, 1) < 0) /* send with padding */
693: return -1;
694: if ((len -= pktsize) <= 0)
695: break;
696: message += pktsize;
697: }
698: return 0;
699: }
700:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.