00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014 #include <sys/types.h>
00015 #include <sys/stat.h>
00016 #include <sys/wait.h>
00017 #include <stdio.h>
00018 #include <stdlib.h>
00019 #include <fcntl.h>
00020 #include <errno.h>
00021 #include <unistd.h>
00022 #include <string.h>
00023 #include <time.h>
00024 #include <net/hton.h>
00025 #include <net/gen/in.h>
00026 #include <net/gen/inet.h>
00027 #include <net/gen/tcp.h>
00028
00029 #include "ftpd.h"
00030 #include "access.h"
00031 #include "file.h"
00032 #include "net.h"
00033
00034 _PROTOTYPE(static int fdxcmd, (int cmd, char *arg));
00035 _PROTOTYPE(static int endfdxcmd, (int fd));
00036 _PROTOTYPE(static int asciisize, (char *filename, unsigned long *filesize));
00037 _PROTOTYPE(static int cnvtfile, (char *name, char **name2));
00038 _PROTOTYPE(static int procfile, (char *name));
00039 _PROTOTYPE(static unsigned long fsize, (char *fname));
00040 _PROTOTYPE(static int sendfile, (char *name, int xmode));
00041 _PROTOTYPE(static int recvfile, (char *name, int xmode));
00042 _PROTOTYPE(static char *uniqname, (void));
00043 _PROTOTYPE(static int docrc, (char *buff, int xmode));
00044 _PROTOTYPE(static int dofdet, (char *buff));
00045 _PROTOTYPE(static char *path, (char *fname));
00046
00047 #define SEND_FILE 0
00048 #define SEND_NLST 1
00049 #define SEND_LIST 2
00050
00051 #define RECV_FILE 0
00052 #define RECV_APND 1
00053 #define RECV_UNIQ 2
00054
00055 #define CNVT_ERROR 0
00056 #define CNVT_NONE 1
00057 #define CNVT_TAR 2
00058 #define CNVT_TAR_Z 3
00059 #define CNVT_COMP 4
00060 #define CNVT_TAR_GZ 5
00061 #define CNVT_GZIP 6
00062 #define CNVT_UNCOMP 7
00063
00064
00065 #define PROG_FTPDSH "ftpdsh"
00066 #define CMD_NLST 1
00067 #define CMD_LIST 2
00068 #define CMD_CRC 3
00069
00070 static char *msg550 = "550 %s %s.\r\n";
00071
00072 static unsigned long file_restart = 0;
00073
00074 static char rnfr[256];
00075 static char buffer[8192];
00076 static char bufout[8192];
00077
00078 static cmdpid = -1;
00079
00080
00081 int doALLO(buff)
00082 char *buff;
00083 {
00084 printf("202 ALLO command not needed at this site.\r\n");
00085
00086 return(GOOD);
00087 }
00088
00089
00090 int doAPPE(buff)
00091 char *buff;
00092 {
00093 return(recvfile(buff, RECV_APND));
00094 }
00095
00096
00097 int doCDUP(buff)
00098 char *buff;
00099 {
00100 if(ChkLoggedIn())
00101 return(GOOD);
00102
00103 return(doCWD(".."));
00104 }
00105
00106
00107 int doCWD(buff)
00108 char *buff;
00109 {
00110 if(ChkLoggedIn())
00111 return(GOOD);
00112
00113 if(chdir(buff))
00114 printf(msg550, buff, strerror(errno));
00115 else {
00116 showmsg("250", ".ftpd_msg");
00117 printf("250 %s command okay.\r\n", line);
00118 }
00119
00120 return(GOOD);
00121 }
00122
00123
00124 int doDELE(buff)
00125 char *buff;
00126 {
00127 if(ChkLoggedIn())
00128 return(GOOD);
00129
00130 if(anonymous) {
00131 printf("550 Command not allowed for anonymous user\r\n");
00132 return(GOOD);
00133 }
00134
00135 if(unlink(buff))
00136 printf(msg550, buff, strerror(errno));
00137 else {
00138 printf("250 File \"%s\" deleted.\r\n", buff);
00139 logit("DELE", path(buff));
00140 }
00141
00142 return(GOOD);
00143 }
00144
00145
00146 int doLIST(buff)
00147 char *buff;
00148 {
00149 file_restart = 0;
00150
00151 return(sendfile(buff, SEND_LIST));
00152 }
00153
00154
00155 int doMDTM(buff)
00156 char *buff;
00157 {
00158 struct stat st;
00159 struct tm *t;
00160
00161 if(ChkLoggedIn())
00162 return(GOOD);
00163
00164 if(stat(buff, &st)) {
00165 printf(msg550, buff, strerror(errno));
00166 return(GOOD);
00167 }
00168
00169 if((st.st_mode & S_IFMT) != S_IFREG) {
00170 printf("550 Not a regular file.\r\n");
00171 return(GOOD);
00172 }
00173
00174 t = gmtime(&st.st_mtime);
00175
00176 printf("215 %04d%02d%02d%02d%02d%02d\r\n",
00177 t->tm_year+1900, t->tm_mon+1, t->tm_mday,
00178 t->tm_hour, t->tm_min, t->tm_sec);
00179
00180 return(GOOD);
00181 }
00182
00183
00184 int doMODE(buff)
00185 char *buff;
00186 {
00187 switch(*buff) {
00188 case 'b':
00189 case 'B':
00190 printf("200 Mode set to %c.\r\n", *buff);
00191 mode = MODE_B;
00192 break;
00193 case 's':
00194 case 'S':
00195 printf("200 Mode set to %c.\r\n", *buff);
00196 mode = MODE_S;
00197 break;
00198 default:
00199 printf("501 Unknown mode %c.\r\n", *buff);
00200 }
00201
00202 return(GOOD);
00203 }
00204
00205
00206 int doMKD(buff)
00207 char *buff;
00208 {
00209 if(ChkLoggedIn())
00210 return(GOOD);
00211
00212 if(anonymous) {
00213 printf("550 Command not allowed for anonymous user\r\n");
00214 return(GOOD);
00215 }
00216
00217 if(mkdir(buff, 0777))
00218 printf(msg550, buff, strerror(errno));
00219 else {
00220 printf("257 \"%s\" directory created.\r\n", buff);
00221 logit("MKD ", path(buff));
00222 }
00223
00224 return(GOOD);
00225 }
00226
00227
00228 int doNLST(buff)
00229 char *buff;
00230 {
00231 file_restart = 0;
00232
00233 return(sendfile(buff, SEND_NLST));
00234 }
00235
00236
00237 int doPWD(buff)
00238 char *buff;
00239 {
00240 char dir[128];
00241
00242 if(ChkLoggedIn())
00243 return(GOOD);
00244
00245 if(getcwd(dir, sizeof(dir)) == (char *)NULL)
00246 printf(msg550, buff, strerror(errno));
00247 else
00248 printf("257 \"%s\" is current directory.\r\n", dir);
00249
00250 return(GOOD);
00251 }
00252
00253
00254 int doREST(buff)
00255 char *buff;
00256 {
00257 if(ChkLoggedIn())
00258 return(GOOD);
00259
00260 file_restart = atol(buff);
00261
00262 printf("350 Next file transfer will restart at %lu.\r\n", file_restart);
00263
00264 return(GOOD);
00265 }
00266
00267
00268 int doRETR(buff)
00269 char *buff;
00270 {
00271 return(sendfile(buff, SEND_FILE));
00272 }
00273
00274
00275 int doRMD(buff)
00276 char *buff;
00277 {
00278 if(ChkLoggedIn())
00279 return(GOOD);
00280
00281 if(anonymous) {
00282 printf("550 Command not allowed for anonymous user\r\n");
00283 return(GOOD);
00284 }
00285
00286 if(rmdir(buff))
00287 printf(msg550, buff, strerror(errno));
00288 else {
00289 printf("250 Directory \"%s\" deleted.\r\n", buff);
00290 logit("RMD ", path(buff));
00291 }
00292
00293 return(GOOD);
00294 }
00295
00296
00297 int doRNFR(buff)
00298 char *buff;
00299 {
00300 if(ChkLoggedIn())
00301 return(GOOD);
00302
00303 if(anonymous) {
00304 printf("550 Command not allowed for anonymous user\r\n");
00305 return(GOOD);
00306 }
00307
00308 strncpy(rnfr, buff, sizeof(rnfr));
00309 rnfr[sizeof(rnfr)-1] = '\0';
00310
00311 printf("350 Got RNFR waiting for RNTO.\r\n");
00312
00313 return(GOOD);
00314 }
00315
00316
00317 int doRNTO(buff)
00318 char *buff;
00319 {
00320 if(ChkLoggedIn())
00321 return(GOOD);
00322
00323 if(anonymous) {
00324 printf("550 Command not allowed for anonymous user\r\n");
00325 return(GOOD);
00326 }
00327
00328 if(rnfr[0] == '\0') {
00329 printf("550 Rename failed.\r\n");
00330 return(GOOD);
00331 }
00332
00333 if(rename(rnfr, buff) < 0)
00334 printf("550 Rename failed. Error %s\r\n", strerror(errno));
00335 else {
00336 printf("250 Renamed %s to %s.\r\n", rnfr, buff);
00337 logit("RNFR", path(rnfr));
00338 logit("RNTO", path(buff));
00339 }
00340
00341 rnfr[0] = '\0';
00342
00343 return(GOOD);
00344 }
00345
00346
00347 static int docrc(buff, xmode)
00348 char *buff;
00349 int xmode;
00350 {
00351 unsigned short cs;
00352 long fs;
00353 int fd;
00354 int s;
00355 char *p;
00356
00357 if((fd = fdxcmd(CMD_CRC, buff)) < 0) {
00358 printf("501 Could not obtain CRC.\r\n");
00359 return(GOOD);
00360 }
00361
00362 if(xmode == 0)
00363 printf("202-SITE CRC \"%s\"\r\n", buff);
00364
00365 while(1) {
00366 p = buffer;
00367 while(1) {
00368 if((s = read(fd, p, 1)) != 1) {
00369 if(xmode == 0)
00370 printf("202 SITE CRC DONE.\r\n");
00371 else
00372 printf("501 Could not obtain CRC.\r\n");
00373 endfdxcmd(fd);
00374 return(GOOD);
00375 }
00376 if(*p == '\n') {
00377 *p++ = '\r';
00378 *p++ = '\n';
00379 *p = '\0';
00380 break;
00381 }
00382 p++;
00383 }
00384 if(xmode != 0)
00385 break;
00386 printf(" %s", buffer);
00387 }
00388
00389 cs = atoi(buffer);
00390
00391 fs = atol(buffer+6);
00392
00393 printf("202 CRC %05u %ld.\r\n", cs, fs);
00394
00395 endfdxcmd(fd);
00396
00397 return(GOOD);
00398 }
00399
00400
00401 int doSITE(buff)
00402 char *buff;
00403 {
00404 char *args;
00405
00406 if(ChkLoggedIn())
00407 return(GOOD);
00408
00409
00410 strncpy(line, buff, sizeof(line));
00411 line[sizeof(line)-1] = '\0';
00412
00413 cvtline(&args);
00414
00415 if(!strcmp(line, "CRC") || !strcmp(line, "CCRC"))
00416 return(docrc(args, strcmp(line, "CRC")));
00417
00418 if(!strcmp(line, "FDET"))
00419 return(dofdet(args));
00420
00421 printf("501 Unknown SITE command %s.\r\n", line);
00422
00423 return(GOOD);
00424 }
00425
00426 static unsigned long fsize(fname)
00427 char *fname;
00428 {
00429 struct stat st;
00430 unsigned long fs = 0L;
00431
00432 if(stat(fname, &st))
00433 return(fs);
00434
00435 if((st.st_mode & S_IFMT) != S_IFREG)
00436 return(fs);
00437
00438 if(type == TYPE_A)
00439 return(fs);
00440
00441 fs = st.st_size;
00442
00443 return(fs);
00444 }
00445
00446
00447 int doSIZE(buff)
00448 char *buff;
00449 {
00450 struct stat st;
00451 unsigned long filesize;
00452
00453 if(ChkLoggedIn())
00454 return(GOOD);
00455
00456 if(stat(buff, &st)) {
00457 printf(msg550, buff, strerror(errno));
00458 return(GOOD);
00459 }
00460
00461 if((st.st_mode & S_IFMT) != S_IFREG) {
00462 printf("550 Not a regular file.\r\n");
00463 return(GOOD);
00464 }
00465
00466 filesize = st.st_size;
00467
00468 if(type == TYPE_A)
00469 if(asciisize(buff, &filesize))
00470 return(GOOD);
00471
00472 printf("215 %lu\r\n", filesize);
00473
00474 return(GOOD);
00475 }
00476
00477
00478 int doSTAT(buff)
00479 char *buff;
00480 {
00481 time_t now;
00482 struct tm *tm;
00483 int fd;
00484 int s;
00485
00486 if(!*buff) {
00487 (void) time(&now);
00488 tm = localtime(&now);
00489 printf("211-%s(%s:%u) FTP server status:\r\n",
00490 myhostname, inet_ntoa(myipaddr), ntohs(myport));
00491 printf(" Version %s ", FtpdVersion);
00492 printf("%s, %02d %s %d %02d:%02d:%02d %s\r\n", days[tm->tm_wday],
00493 tm->tm_mday, months[tm->tm_mon], 1900+tm->tm_year,
00494 tm->tm_hour, tm->tm_min, tm->tm_sec, tzname[tm->tm_isdst]);
00495 printf(" Connected to %s:%u\r\n", inet_ntoa(rmtipaddr), ntohs(rmtport));
00496 if(!loggedin)
00497 printf(" Not logged in\r\n");
00498 else
00499 printf(" Logged in %s\r\n", username);
00500 printf(" MODE: %s\r\n",(mode == MODE_B) ? "Block" : "Stream");
00501 printf(" TYPE: %s\r\n",(type == TYPE_A) ? "Ascii" : "Binary");
00502 printf("211 End of status\r\n");
00503 return(GOOD);
00504 }
00505
00506 if(ChkLoggedIn())
00507 return(GOOD);
00508
00509 printf("211-Status of %s:\r\n", buff);
00510
00511 if((fd = fdxcmd(CMD_LIST, buff)) < 0)
00512 printf(" Could not retrieve status");
00513 else {
00514 while((s = read(fd, buffer, 1)) == 1) {
00515 if(*buffer == '\n')
00516 printf("\r\n");
00517 else
00518 printf("%c", *buffer);
00519 }
00520 endfdxcmd(fd);
00521 }
00522
00523 printf("211 End of status\r\n");
00524
00525 return(GOOD);
00526 }
00527
00528
00529 int doSTOR(buff)
00530 char *buff;
00531 {
00532 return(recvfile(buff, RECV_FILE));
00533 }
00534
00535
00536 int doSTOU(buff)
00537 char *buff;
00538 {
00539 return(recvfile(buff, RECV_UNIQ));
00540 }
00541
00542
00543 int doSTRU(buff)
00544 char *buff;
00545 {
00546 switch(*buff) {
00547 case 'f':
00548 case 'F':
00549 printf("200 Structure set to %c.\r\n", *buff);
00550 break;
00551 default:
00552 printf("501 Unknown structure %c.\r\n", *buff);
00553 }
00554
00555 return(GOOD);
00556 }
00557
00558
00559 int doSYST(buff)
00560 char *buff;
00561 {
00562 printf("215 UNIX Type: L8\r\n");
00563
00564 return(GOOD);
00565 }
00566
00567
00568 int doTYPE(buff)
00569 char *buff;
00570 {
00571 if(*(buff+1) != '\0') {
00572 printf("501 Syntax error in parameters.\r\n");
00573 return(GOOD);
00574 }
00575
00576 switch(*buff) {
00577 case 'A':
00578 case 'a':
00579 type = TYPE_A;
00580 printf("200 Type set to A.\r\n");
00581 break;
00582 case 'I':
00583 case 'i':
00584 type = TYPE_I;
00585 printf("200 Type set to I.\r\n");
00586 break;
00587 default:
00588 printf("501 Invalid type %c.\r\n", *buff);
00589 }
00590
00591 return(GOOD);
00592 }
00593
00594 static int fdxcmd(cmd, arg)
00595 int cmd;
00596 char *arg;
00597 {
00598 char xcmd[3];
00599 char *argv[5];
00600 int fds[2];
00601 char *smallenv[] = { "PATH=/bin:/usr/bin:/usr/local/bin", NULL, NULL };
00602
00603 if((smallenv[1] = getenv("TZ")) != NULL) smallenv[1] -= 3;
00604
00605 sprintf(xcmd, "%d", cmd);
00606
00607 argv[0] = PROG_FTPDSH;
00608 argv[1] = xcmd;
00609 argv[2] = arg;
00610 argv[3] = (char *)NULL;
00611
00612 if(pipe(fds) < 0)
00613 return(-1);
00614
00615 if((cmdpid = fork()) < 0) {
00616 close(fds[0]);
00617 close(fds[1]);
00618 return(-1);
00619 }
00620
00621 if(cmdpid == 0) {
00622 close(fds[0]);
00623 close(0);
00624 open("/dev/null", O_RDONLY);
00625 dup2(fds[1], 1);
00626 dup2(fds[1], 2);
00627 close(fds[1]);
00628 sprintf(argv[0], "/bin/%s", PROG_FTPDSH);
00629 execve(argv[0], argv, smallenv);
00630 sprintf(argv[0], "/usr/bin/%s", PROG_FTPDSH);
00631 execve(argv[0], argv, smallenv);
00632 sprintf(argv[0], "/usr/local/bin/%s", PROG_FTPDSH);
00633 execve(argv[0], argv, smallenv);
00634 exit(0);
00635 }
00636
00637 close(fds[1]);
00638
00639 return(fds[0]);
00640 }
00641
00642
00643 static int endfdxcmd(fd)
00644 int fd;
00645 {
00646 int s;
00647 int cs;
00648
00649 close(fd);
00650
00651 if(cmdpid == -1)
00652 return(0);
00653
00654 s = waitpid(cmdpid, &cs, 0);
00655
00656 cmdpid = -1;
00657
00658 return(0);
00659 }
00660
00661
00662
00663 static int asciisize(filename, filesize)
00664 char *filename;
00665 unsigned long *filesize;
00666 {
00667 unsigned long count;
00668 int fd;
00669 char *p, *pp;
00670 int cnt;
00671
00672 if((fd = open(filename, O_RDONLY)) < 0) {
00673 printf(msg550, filename, strerror(errno));
00674 return(-1);
00675 }
00676
00677 count = 0;
00678
00679 while((cnt = read(fd, buffer, sizeof(buffer))) > 0) {
00680 count += cnt;
00681 p = buffer;
00682 while(cnt > 0)
00683 if((pp = memchr(p, '\n', cnt)) != (char *)NULL) {
00684 count++;
00685 cnt = cnt - 1 - (pp - p);
00686 p = pp + 1;
00687 } else
00688 break;
00689 }
00690
00691 if(cnt == 0) {
00692 *filesize = count;
00693 close(fd);
00694 return(0);
00695 }
00696
00697 printf(msg550, filename, strerror(errno));
00698
00699 close(fd);
00700
00701 return(-1);
00702 }
00703
00704
00705 static int cnvtfile(name, name2)
00706 char *name;
00707 char **name2;
00708 {
00709 struct stat st;
00710 static char fname[256];
00711 char *p;
00712 int cmode;
00713
00714 if(!stat(name, &st))
00715 if((st.st_mode & S_IFMT) != S_IFREG) {
00716 printf("550 Not a regular file.\r\n");
00717 return(CNVT_ERROR);
00718 } else
00719 return(CNVT_NONE);
00720
00721 if(errno != ENOENT) {
00722 printf(msg550, name, strerror(errno));
00723 return(CNVT_ERROR);
00724 }
00725
00726
00727 strncpy(fname, name, sizeof(fname));
00728 fname[sizeof(fname)-1] = '\0';
00729
00730 p = fname + strlen(fname);
00731 cmode = CNVT_ERROR;
00732 while(p > fname && cmode == CNVT_ERROR) {
00733 if(*p == '.') {
00734 if(!strcmp(p, ".tar"))
00735 cmode = CNVT_TAR;
00736 else
00737 if(!strcmp(p, ".tar.Z"))
00738 cmode = CNVT_TAR_Z;
00739 else
00740 if(!strcmp(p, ".Z"))
00741 cmode = CNVT_COMP;
00742 else
00743 if(!strcmp(p, ".tar.gz"))
00744 cmode = CNVT_TAR_GZ;
00745 else
00746 if(!strcmp(p, ".gz"))
00747 cmode = CNVT_GZIP;
00748
00749 if (cmode != CNVT_ERROR) {
00750
00751 *p = '\0';
00752 if (!stat(fname, &st)) break;
00753 *p = '.';
00754 cmode = CNVT_ERROR;
00755 }
00756 }
00757 p--;
00758 }
00759
00760 if(cmode == CNVT_ERROR) {
00761 printf(msg550, fname, strerror(errno));
00762 return(CNVT_ERROR);
00763 }
00764
00765 if(cmode == CNVT_COMP || cmode == CNVT_GZIP || cmode == CNVT_UNCOMP)
00766 if((st.st_mode & S_IFMT) != S_IFREG) {
00767 printf("550 Not a regular file.\r\n");
00768 return(CNVT_ERROR);
00769 }
00770
00771 *name2 = fname;
00772
00773 return(cmode);
00774 }
00775
00776 static int procfile(name)
00777 char *name;
00778 {
00779 int cmd;
00780 int fd;
00781 char *name2;
00782
00783 cmd = cnvtfile(name, &name2);
00784
00785 switch(cmd) {
00786 case CNVT_TAR:
00787 fd = fdxcmd(cmd + 10, name2);
00788 break;
00789 case CNVT_TAR_Z:
00790 fd = fdxcmd(cmd + 10, name2);
00791 break;
00792 case CNVT_COMP:
00793 fd = fdxcmd(cmd + 10, name2);
00794 break;
00795 case CNVT_TAR_GZ:
00796 fd = fdxcmd(cmd + 10, name2);
00797 break;
00798 case CNVT_GZIP:
00799 fd = fdxcmd(cmd + 10, name2);
00800 break;
00801 case CNVT_UNCOMP:
00802 fd = fdxcmd(cmd + 10, name2);
00803 break;
00804 case CNVT_NONE:
00805 fd = open(name, O_RDONLY);
00806 break;
00807 case CNVT_ERROR:
00808 default:
00809 return(-1);
00810 }
00811
00812 if(fd < 0)
00813 printf(msg550, name, strerror(errno));
00814
00815 return(fd);
00816 }
00817
00818
00819 static int sendfile(name, xmode)
00820 char *name;
00821 int xmode;
00822 {
00823 char *fname;
00824 int fd, s;
00825 time_t datastart, dataend;
00826 unsigned long datacount;
00827 long kbs;
00828 char c;
00829 char *p;
00830 char *op, *ope;
00831 off_t sp;
00832 int doascii;
00833 unsigned long fs;
00834 char block[3];
00835
00836 if(ChkLoggedIn())
00837 return(GOOD);
00838
00839 switch(xmode) {
00840 case SEND_NLST:
00841 fname = "NLST";
00842 fd = fdxcmd(CMD_NLST, name);
00843 if(fd < 0)
00844 printf(msg550, name, strerror(errno));
00845 break;
00846 case SEND_LIST:
00847 fname = "LIST";
00848 fd = fdxcmd(CMD_LIST, name);
00849 if(fd < 0)
00850 printf(msg550, name, strerror(errno));
00851 break;
00852 default:
00853 fname = name;
00854 fd = procfile(name);
00855 if(fd < 0)
00856 logit("FAIL", path(fname));
00857 else
00858 logit("SEND", path(fname));
00859 }
00860
00861 if(fd < 0)
00862 return(GOOD);
00863
00864
00865 if(file_restart) {
00866 if(type == TYPE_A) {
00867 sp = 0;
00868 while(sp < file_restart) {
00869 sp++;
00870 s = read(fd, buffer, 1);
00871 if(s < 0) {
00872 printf(msg550, fname, strerror(errno));
00873 endfdxcmd(fd);
00874 file_restart = 0;
00875 return(GOOD);
00876 }
00877 if(s == 0) break;
00878 if(*buffer == '\n')
00879 sp++;
00880 }
00881 } else {
00882 sp = lseek(fd, file_restart, SEEK_SET);
00883 if(sp == -1) {
00884 printf(msg550, fname, strerror(errno));
00885 endfdxcmd(fd);
00886 file_restart = 0;
00887 return(GOOD);
00888 }
00889 }
00890 if(sp != file_restart) {
00891 printf("550 File restart point error. %lu not %lu\r\n", sp, file_restart);
00892 endfdxcmd(fd);
00893 file_restart = 0;
00894 return(GOOD);
00895 }
00896 }
00897 file_restart = 0;
00898
00899 fs = fsize(fname);
00900 if(fs == 0L)
00901 printf("%03d File %s okay. Opening data connection.\r\n",
00902 ftpdata_fd >= 0 ? 125 : 150, fname);
00903 else
00904 printf("%03d Opening %s mode data connection for %s (%ld bytes).\r\n",
00905 ftpdata_fd >= 0 ? 125 : 150,
00906 type == TYPE_A ? "ASCII" : "BINARY",
00907 fname, fs);
00908 fflush(stdout);
00909
00910 #ifdef DEBUG
00911 fprintf(logfile, "After 125/150 b4 DataConnect\n");
00912 fflush(logfile);
00913 #endif
00914
00915 if(DataConnect()) {
00916 endfdxcmd(fd);
00917 return(GOOD);
00918 }
00919
00920 #ifdef DEBUG
00921 fprintf(logfile, "After DataConnect\n");
00922 fflush(logfile);
00923 fprintf(logfile, "ftpd: parent %d start sendfile \n", getpid());
00924 fflush(logfile);
00925 #endif
00926
00927
00928 doascii = (type == TYPE_A) ||
00929 ((xmode == SEND_LIST) || (xmode == SEND_NLST));
00930 datacount = 0;
00931 time(&datastart);
00932 op = bufout; ope = bufout + sizeof(bufout) - 3;
00933 while((s = read(fd, buffer, sizeof(buffer))) > 0) {
00934 #ifdef DEBUG
00935 fprintf(logfile, "sendfile read %d\n", s); fflush(logfile);
00936 #endif
00937 datacount += s;
00938 if(doascii) {
00939 p = buffer;
00940 while(s-- > 0) {
00941 c = *p++;
00942 if(c == '\n') {
00943 *op++ = '\r';
00944 datacount++;
00945 }
00946 *op++ = c;
00947 if(op >= ope) {
00948 if(mode == MODE_B) {
00949 block[0] = '\0';
00950 *(u16_t *)&block[1] = htons(op - bufout);
00951 write(ftpdata_fd, block, sizeof(block));
00952 }
00953 write(ftpdata_fd, bufout, op - bufout);
00954 op = bufout;
00955 }
00956 }
00957 } else {
00958 if(mode == MODE_B) {
00959 block[0] = '\0';
00960 *(u16_t *)&block[1] = htons(s);
00961 write(ftpdata_fd, block, sizeof(block));
00962 }
00963 s = write(ftpdata_fd, buffer, s);
00964 }
00965 }
00966 if(op > bufout) {
00967 if(mode == MODE_B) {
00968 block[0] = MODE_B_EOF;
00969 *(u16_t *)&block[1] = htons(op - bufout);
00970 write(ftpdata_fd, block, sizeof(block));
00971 }
00972 write(ftpdata_fd, bufout, op - bufout);
00973 } else
00974 if(mode == MODE_B) {
00975 block[0] = MODE_B_EOF;
00976 *(u16_t *)&block[1] = htons(0);
00977 write(ftpdata_fd, block, sizeof(block));
00978 }
00979 time(&dataend);
00980
00981 #ifdef DEBUG
00982 fprintf(logfile, "ftpd: parent %d end sendfile \n", getpid());
00983 fflush(logfile);
00984 #endif
00985
00986 endfdxcmd(fd);
00987 if(mode != MODE_B) {
00988 close(ftpdata_fd);
00989 ftpdata_fd = -1;
00990 }
00991
00992 if(dataend == datastart) dataend++;
00993 kbs = (datacount * 100 / (dataend - datastart)) / 1024;
00994
00995 if(s < 0)
00996 printf("451 Transfer aborted.\r\n");
00997 else
00998 printf("%03d Transfer finished successfully. %ld.%02d KB/s\r\n",
00999 mode == MODE_B ? 250 : 226,
01000 (long)(kbs / 100), (int)(kbs % 100));
01001
01002 return(GOOD);
01003 }
01004
01005 static int recvfile(name, xmode)
01006 char *name;
01007 int xmode;
01008 {
01009 char *fname;
01010 time_t datastart, dataend;
01011 unsigned long datacount;
01012 long kbs;
01013 char c;
01014 char *p;
01015 char *op, *ope;
01016 int fd, oflag;
01017 int s;
01018 int gotcr;
01019 off_t sp;
01020 char block[3];
01021 unsigned short cnt;
01022
01023 if(ChkLoggedIn())
01024 return(GOOD);
01025
01026 fname = name;
01027
01028 switch(xmode) {
01029 case RECV_APND:
01030 oflag = O_WRONLY | O_APPEND;
01031 break;
01032 case RECV_UNIQ:
01033 fname = uniqname();
01034 oflag = O_WRONLY | O_CREAT;
01035 break;
01036 default:
01037 oflag = O_WRONLY | O_CREAT | O_TRUNC;
01038 }
01039
01040 if(file_restart)
01041 oflag = O_RDWR;
01042
01043 fd = open(fname, oflag, (anonymous ? 0000:0600));
01044
01045 if(fd < 0) {
01046 printf(msg550, fname, strerror(errno));
01047 return(GOOD);
01048 }
01049
01050
01051 logit("RECV", path(fname));
01052
01053
01054 if(file_restart) {
01055 if(type == TYPE_A) {
01056 sp = 0;
01057 while(sp < file_restart) {
01058 sp++;
01059 s = read(fd, buffer, 1);
01060 if(s < 0) {
01061 printf(msg550, fname, strerror(errno));
01062 close(fd);
01063 file_restart = 0;
01064 return(GOOD);
01065 }
01066 if(s == 0) break;
01067 if(*buffer == '\n')
01068 sp++;
01069 }
01070 } else {
01071 sp = lseek(fd, file_restart, SEEK_SET);
01072 if(sp == -1) {
01073 printf(msg550, fname, strerror(errno));
01074 close(fd);
01075 file_restart = 0;
01076 return(GOOD);
01077 }
01078 }
01079 if(sp != file_restart) {
01080 printf("550 File restart point error. %lu not %lu\r\n", sp, file_restart);
01081 close(fd);
01082 file_restart = 0;
01083 return(GOOD);
01084 }
01085 }
01086 file_restart = 0;
01087
01088 if(xmode == RECV_UNIQ)
01089 printf("%03d FILE: %s\r\n",
01090 ftpdata_fd >= 0 ? 125 : 150, fname);
01091 else
01092 printf("%03d File %s okay. Opening data connection.\r\n",
01093 ftpdata_fd >= 0 ? 125 : 150, fname);
01094 fflush(stdout);
01095
01096 if(DataConnect()) {
01097 close(fd);
01098 return(GOOD);
01099 }
01100
01101 #ifdef DEBUG
01102 fprintf(logfile, "ftpd: parent %d start recvfile \n", getpid());
01103 fflush(logfile);
01104 #endif
01105
01106
01107 datacount = 0;
01108 gotcr = 0;
01109 op = bufout; ope = bufout + sizeof(bufout) - 3;
01110 cnt = 0;
01111 time(&datastart);
01112 while(1) {
01113 if(mode != MODE_B)
01114 cnt = sizeof(buffer);
01115 else
01116 if(cnt == 0) {
01117 s = read(ftpdata_fd, block, sizeof(block));
01118 cnt = ntohs(*(u16_t *)&block[1]);
01119 s = 0;
01120 if(cnt == 0 && block[0] & MODE_B_EOF)
01121 break;
01122 }
01123 s = read(ftpdata_fd, buffer, cnt > sizeof(buffer) ? sizeof(buffer) : cnt);
01124 if(s <= 0) break;
01125 cnt -= s;
01126 datacount += (long)s;
01127 if(type == TYPE_A) {
01128 p = buffer;
01129 while(s-- > 0) {
01130 c = *p++;
01131 if(gotcr) {
01132 gotcr = 0;
01133 if(c != '\n')
01134 *op++ = '\r';
01135 }
01136 if(c == '\r')
01137 gotcr = 1;
01138 else
01139 *op++ = c;
01140 if(op >= ope) {
01141 write(fd, bufout, op - bufout);
01142 op = bufout;
01143 }
01144 }
01145 } else
01146 write(fd, buffer, s);
01147 if(cnt == 0 && mode == MODE_B && block[0] & MODE_B_EOF) {
01148 s = 0;
01149 break;
01150 }
01151 }
01152 if(gotcr)
01153 *op++ = '\r';
01154 if(op > bufout)
01155 write(fd, bufout, op - bufout);
01156 time(&dataend);
01157
01158 #ifdef DEBUG
01159 fprintf(logfile, "ftpd: parent %d end recvfile \n", getpid());
01160 fflush(logfile);
01161 #endif
01162
01163 close(fd);
01164 if(mode != MODE_B) {
01165 close(ftpdata_fd);
01166 ftpdata_fd = -1;
01167 }
01168
01169 if(dataend == datastart) dataend++;
01170 kbs = (datacount * 100 / (dataend - datastart)) / 1024;
01171
01172 if((mode == MODE_B && cnt != 0) || s != 0)
01173 printf("451 Transfer aborted.\r\n");
01174 else {
01175 printf("%03d Transfer finished successfully. ",
01176 mode == MODE_B ? 250 : 226);
01177 if(xmode == RECV_UNIQ)
01178 printf("Unique file %s. ", fname);
01179 printf("%ld.%02d KB/s\r\n", (long)(kbs / 100), (int)(kbs % 100));
01180 }
01181
01182 return(GOOD);
01183 }
01184
01185 static char *uniqname()
01186 {
01187 static char uniq[32];
01188 int i;
01189 struct stat st;
01190
01191 for(i = 0; i < 1000; i++) {
01192 sprintf(uniq, "ftpd%d%d", getpid(), i);
01193 if(stat(uniq, &st) == -1)
01194 return(uniq);
01195 }
01196 return(uniq);
01197 }
01198
01199 static char *spath[256];
01200 static char *path(fname)
01201 char *fname;
01202 {
01203 char dir[128];
01204
01205 if(getcwd(dir, sizeof(dir)) == (char *)NULL)
01206 sprintf(dir, "???");
01207
01208 if(fname[0] == '/')
01209 sprintf((char *)spath, "%s%s", newroot, fname);
01210 else
01211 if(dir[1] == '\0')
01212 sprintf((char *)spath, "%s%s%s", newroot, dir, fname);
01213 else
01214 sprintf((char *)spath, "%s%s/%s", newroot, dir, fname);
01215
01216 return((char *)spath);
01217 }
01218
01219
01220 static int dofdet(buff)
01221 char *buff;
01222 {
01223 struct stat st;
01224 char ft;
01225
01226 if(ChkLoggedIn())
01227 return(GOOD);
01228
01229 if(stat(buff, &st)) {
01230 printf("501 Could not obtain file detail.\r\n");
01231 return(GOOD);
01232 }
01233 switch(st.st_mode & S_IFMT) {
01234 case S_IFIFO: ft = 'p'; break;
01235 case S_IFCHR: ft = 'c'; break;
01236 case S_IFDIR: ft = 'd'; break;
01237 case S_IFBLK: ft = 'b'; break;
01238 case S_IFREG: ft = 'f'; break;
01239 default: ft = '?'; break;
01240 }
01241 printf("202 %c %u %u %u %u %u %lu %lu\r\n",
01242 ft,
01243 st.st_rdev >> 8,
01244 st.st_rdev & 0xff,
01245 st.st_uid,
01246 st.st_gid,
01247 st.st_mode,
01248 st.st_size,
01249 st.st_mtime);
01250
01251 return(GOOD);
01252 }