|
|
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: printmsg(M_SPOOL, "cline[%d]:\t%\"%s\"", i, clinep[i]);
314: sp = NULL;
315: }
316:
317:
318: /* If the last field of a parsed command line is NOT null, then
319: * there is something wrong with the line parsed. Leave a message
320: * to this affect in the logs, and print the offending line there
321: * as well. Abort processing this file.
322:
323: * It has not yet been determined what affects this will have.
324: * It may keep other requests from the site which is expecting to
325: * receive files from receving all of the files it expects.
326:
327: * the following is a short description of how this was called:
328:
329: sendf() -> calls cdotcmd() until 'complete' (dcp.c)
330: cdotcmd() -> calls getcline() until a non-zero
331: value is returned. When a non zero
332: value is returned, the C. file being
333: read is closed and deleted. A 'B' is
334: then returned back to sendf()
335: getcline() -> calls sepcline (breaks out the C. fields)
336:
337: * Bob Hemedinger 01/27/92
338: */
339:
340: /* 01/30/92: removed the return statement. We WANT to continue
341: * if we don't see the NULL terminator for compatibility with
342: * other variants.
343: */
344:
345: if (clinep[9] != NULL) {
346: plog(M_SPOOL, "Error parsing command 'C.' file");
347: plog(M_SPOOL, "last sepcline field not null");
348: plog(M_SPOOL, "Actually parsed: ");
349: plog(M_SPOOL, " %s %s %s %s %s %s %s %s %s",
350: clinep[1], clinep[2], clinep[3],
351: clinep[4], clinep[5], clinep[6],
352: clinep[7], clinep[8], clinep[9]);
353: }
354: nclinep = i;
355: fromfilep = clinep[2];
356: tofilep = clinep[3];
357: usernamep = clinep[4];
358: optionp = clinep[5];
359: spoolfilep = clinep[6];
360: modep = clinep[7];
361: notifyp = clinep[8];
362: if (strcmp(clinep[1], "S") == 0) {
363: sprintf(xfromfile, "%s/%s/%s", SPOOLDIR, rmtname, spoolfilep);
364: if (index(optionp, 'c') != NULL) /* this looks weak */
365: strcpy(xfromfile, fromfilep);
366: } else if (strcmp(clinep[1], "R") == 0) {
367: strcpy(xfromfile, fromfilep);
368: } else if (*clinep[1] == 'H') {
369: ;
370: } else {
371: plog(M_SPOOL, "Unrecog record type %s", cline);
372: printmsg(M_SPOOL, "Unrecog type %s %s %s", cline[1],
373: cline[2], cline[3]);
374: return 1;
375: }
376: return 0;
377: }
378:
379: /*********************** MISC SUB SUB PROTOCOL *************************/
380:
381: /*
382: *
383: * schkdir
384: * scan the dir
385: */
386: schkdir()
387: {
388: char c;
389:
390: c = scandir();
391:
392: if (c == 'Q') {
393: return ('Y');
394: }
395: if (c == 'S') {
396: sprintf(rpacket, "HN");
397: if ((*sendpkt) (rpacket, 0, 1))
398: return cantsend();
399: }
400: return ('B');
401: }
402:
403: /*
404: * endp() end protocol
405: *
406: */
407: endp()
408: {
409:
410: (void) sendmsg("HY");
411: (*closepk) ();
412: return 'P';
413: }
414:
415:
416:
417: /***********************RECEIVE PROTOCOL**********************/
418:
419: /*
420: * r d a t a
421: *
422: * Receive Data
423: */
424: rdata()
425: {
426: int len;
427:
428: if ((*getpkt) (rpacket, &len))
429: return cantread();
430: if (len == 0)
431: return reof();
432: if (write(fpfd, rpacket, len) != len) /* Write the data to the file */
433: return 'Y';
434: bytecount += len;
435: return 'J'; /* Remain in data state */
436: /* changed to J */
437: }
438:
439: /*
440: * reof
441: * handle eof on read.
442: * try to link the temp file to the new name;
443: * if not successful, then copy it.
444: */
445: reof()
446: {
447: int tfpfd;
448: int noperm;
449: double elapsed;
450: int mode;
451: int bytes;
452:
453: noperm = 0;
454: tfpfd = -1;
455: close(fpfd);
456: fpfd = -1;
457: unlink(xtofile);
458: if (link(tempname, xtofile) == -1) {
459: if ((tfpfd = open(tempname, 0)) == -1) {
460: sprintf(reason, "Unable to reread \"%s\"; %s",
461: tempname, sys_errlist[errno]);
462: noperm = 1;
463: } else if ((fpfd = creat(xtofile, 0644)) == -1) {
464: sprintf(reason, "Unable to create \"%s\"; %s (rdata)",
465: xtofile, sys_errlist[errno]);
466: noperm = 1;
467: }
468: if (noperm) {
469: plog(M_TRANSFER, reason);
470: notifystatus(fromfilep, tempname, 0, 0, lstat);
471: if (sendmsg("CN") < 0) {
472: plog(M_SPOOL, "Message CN refused");
473: return cantsend();
474: }
475: if (tfpfd != -1)
476: close(tfpfd);
477: if (fpfd != -1)
478: close(fpfd);
479: return 'F';
480: }
481: while ((bytes = read(tfpfd, bigreadbuf, BIGBUFSZ)) > 0)
482: write(fpfd, bigreadbuf, bytes);
483: close(tfpfd);
484: close(fpfd);
485: fpfd = -1;
486: }
487: unlink(tempname);
488: if ((strlen(modep) > 0) && (mode = getoct(modep)) != 0 &&
489: (chmod(xtofile, getoct(modep)) == -1)) {
490: printmsg(M_TRANSFER, "Unable to change permission");
491: plog(M_TRANSFER,
492: "Unable to change permission to \"%s\" on file \"%s\"",
493: modep, xtofile);
494: }
495: /* now, do the copy. rewind the above file and reread it */
496: /* we ought to do the copy in a temp file, and move it here */
497: printmsg(M_TRANSFER, "transfer complete");
498: ftime(&transferstop);
499: printmsg(M_TRANSFER, "Stop time is %ld.%03d\n",
500: transferstop.time, transferstop.millitm);
501: elapsed =
502: (double)transferstop.time -
503: (double)transferstart.time;
504: elapsed +=
505: ((double)transferstop.millitm -
506: (double)transferstart.millitm) / 1000.0;
507: if (total_errors > 0)
508: plog(M_TRANSFER,
509: "R (OK) %ld bytes, %5.2f seconds, %5.1f Bps, %d error%c",
510: bytecount, (double)elapsed, bytecount / elapsed,
511: total_errors, total_errors == 1 ? ' ' : 's');
512: else
513: plog(M_TRANSFER, "R (OK) %ld bytes, %5.2f seconds, %5.1f Bps",
514: bytecount, (double)elapsed, bytecount / elapsed);
515: notifystatus(fromfilep, xtofile, 0, 1, lstat);
516: printmsg(M_TRANSFER, "returning from rdata");
517: if (sendmsg("CY") < 0) {
518: strcpy(reason, "Message CY refused.");
519: plog(M_TRANSFER, reason);
520: return cantsend();
521: }
522: return 'F';
523: }
524:
525: /*
526: * Analog of cdotcmd. This takes 'S' records or 'R' records
527: * from the other end and dispatches them properly.
528: */
529: rmtcmd()
530: {
531: static char buf[256];
532: char *cp;
533: int noperm;
534:
535: lstat = 0;
536: if (getmsg(buf) < 0) {
537: printmsg(M_LOWPROTO, "in rmtcmd, getmsg says -1");
538: return cantread(); /* was return 0 */
539: }
540: printmsg(M_TRANSFER, "buf[0] is %c", buf[0]);
541: strcpy(cline, buf);
542: sepcline();
543: if (*clinep [1] == 'H') { /* used to be buf [0] */
544: printmsg(M_TRANSFER, "rmtcmd got H, returning C");
545: return 'C';
546: }
547: printmsg(M_TRANSFER, "rmtcmd: buf %d \"%s\"", strlen(S_record),
548: S_record);
549: if (strcmp (clinep [1], "R") == 0) {
550: printmsg(M_INFO, "rmdcmd: send file R");
551: printmsg(M_SPOOL, "Opening %s for sending.", xfromfile);
552: if ((strcmp(perm_value(request_e), "yes") != 0) ||
553: !perm_read(xfromfile)) {
554: sprintf(reason, "Request permission denied: \"%s\"",
555: xfromfile);
556: plog(M_TRANSFER, reason);
557: sendmsg("RN");
558: notifystatus(fromfilep, xtofile, 0, 0, lstat);
559: return 'F';
560: } else {
561: fpfd = open(xfromfile, 0);
562: /* open the file to be sent */
563: if (fpfd == -1) { /* If bad file pointer, give up */
564: sprintf(reason,
565: "Cannot open file \"%s\".", xfromfile);
566: plog(M_TRANSFER, reason);
567: sendmsg("RN");
568: notifystatus(fromfilep, xtofile, 0, 0, lstat);
569: return 'F'; /* was return 'A' */
570: }
571: sendmsg("RY");
572: return sfile();
573: }
574: }
575: printmsg(M_INFO, "rmtcmd: receive file \"%s\"", tofilep);
576: if ((cp = index(optionp, 'c')) != NULL) /* oops, not allowd*/
577: *cp = ' ';
578: noperm = 0;
579: if ((cp = rebuildfn(tofilep)) == NULL) {
580: noperm = 1;
581: sprintf(reason, "No such user as referenced in \"%s\"",
582: tofilep);
583: } else
584: strcpy(xtofile, rebuildfn(tofilep));
585: if (!noperm && !perm_write(xtofile)) {
586: sprintf(reason, "No permission to write file \"%s\"", xtofile);
587: noperm = 1;
588: }
589: if (!noperm && !canwrite(xtofile)) {
590: sprintf(reason, "rmtcmd: Unable to create file \"%s\": %s",
591: xtofile, sys_errlist[errno]);
592: noperm = 1;
593: }
594: if (noperm) {
595: plog(M_TRANSFER, reason);
596: notifystatus(fromfilep, xtofile, 0, 0, lstat);
597: if (sendmsg("SN") < 0)
598: return cantsend();
599: return 'F';
600: }
601: if (sendmsg("SY") < 0) {
602: plog(M_TRANSFER, "Can't send SY");
603: return 'Y';
604: }
605: return rfile();
606: }
607:
608: /*
609: * r f i l e
610: *
611: * Receive File Header
612: */
613: rfile()
614: {
615: printmsg(M_TRANSFER, "Receiving %s as %s", fromfilep, xtofile);
616: /* create temp file name, open it for output */
617: if ((fpfd = creat(mktemp(tempname), 0644)) == -1) {
618: sprintf(reason, "Unable to create \"%s\"; %s",
619: tempname, sys_errlist[errno]);
620: plog(M_TRANSFER, reason);
621: notifystatus(fromfilep, xtofile, 0, 0, lstat);
622: return 'F'; /* Give up if can't */
623: }
624: plog(M_TRANSFER, "R (%s)<-(%s)", xtofile, fromfilep);
625: bytecount = 0;
626: total_errors = 0;
627: ftime(&transferstart);
628: printmsg(M_TRANSFER, "Start time is %ld.%03d\n",
629: transferstart.time, transferstart.millitm);
630: return 'J'; /* Switch to data state */
631: }
632:
633: /*
634: * r i n i t
635: *
636: * Receive Initialization
637: */
638: rinit()
639: {
640: if ((*openpk) ()) {
641: plog(M_TRANSFER, "Unable to get opening packet");
642: return 'Y';
643: }
644: return ('F');
645: }
646:
647: /*
648: * |getmsg()| recieves a null-terminated "conversation-level" message
649: * from the communications channel. This may require one or more packets,
650: * but all of them will be "long-data" packets containing a full 64 bytes.
651: */
652: int getmsg(dest)
653: char *dest;
654: {
655: int len;
656:
657: while(1) {
658: if ((*getpkt)(dest, &len) < 0)
659: return(-1);
660: *(dest + len) = '\0'; /* make sure it's terminated */
661: if (strlen(dest) != len)
662: break; /* we reached the terminator */
663: dest += len;
664: }
665: return( 0 );
666: }
667:
668: /*
669: * |sendmsg(message)| sends a null-terminated "conversation-level" message.
670: */
671: int sendmsg(message)
672: char *message;
673: {
674: int len;
675: len = strlen(message) + 1; /* total length including '\0' */
676:
677: while(1) {
678: if ((*sendpkt)(message, 0, 1) < 0) /* send with padding */
679: return -1;
680: if ((len -= pktsize) <= 0)
681: break;
682: message += pktsize;
683: }
684: return 0;
685: }
686:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.