file.c

Go to the documentation of this file.
00001 /* file.c Copyright 1992-2000 by Michael Temari All Rights Reserved
00002  *
00003  * This file is part of ftpd.
00004  *
00005  * This file handles:
00006  *
00007  *      ALLO APPE CDUP CWD  DELE LIST MDTM MODE MKD  NLST PWD REST RETR
00008  *      RMD  RNFR RNTO SITE SIZE STAT STOR STOU STRU SYST TYPE
00009  *
00010  * 01/25/96 Initial Release     Michael Temari
00011  * 03/09/00                     Michael Temari, <Michael@TemWare.Com>
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 /* allocate, we don't need no stink'n allocate */
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 /* append to a file if it exists */
00090 int doAPPE(buff)
00091 char *buff;
00092 {
00093    return(recvfile(buff, RECV_APND));
00094 }
00095 
00096 /* change to parent directory */
00097 int doCDUP(buff)
00098 char *buff;
00099 {
00100    if(ChkLoggedIn())
00101         return(GOOD);
00102 
00103    return(doCWD(".."));
00104 }
00105 
00106 /* change directory */
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 /* remove a file */
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 /* directory listing */
00146 int doLIST(buff)
00147 char *buff;
00148 {
00149    file_restart = 0;
00150 
00151    return(sendfile(buff, SEND_LIST));
00152 }
00153 
00154 /* file modification time, btw when will this be put into an RFC */
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 /* mode */
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 /* make a directory */
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 /* name listing */
00228 int doNLST(buff)
00229 char *buff;
00230 {
00231    file_restart = 0;
00232 
00233    return(sendfile(buff, SEND_NLST));
00234 }
00235 
00236 /* where are we */
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 /* restart command */
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 /* they want a file */
00268 int doRETR(buff)
00269 char *buff;
00270 {
00271    return(sendfile(buff, SEND_FILE));
00272 }
00273 
00274 /* remove a directory */
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 /* rename from */
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 /* rename to */
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 /* xmode = 0 for multiline crc, xmode <> 0 for single file single line crc */
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 /* site specific */
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 /* file size, btw when will this be put into an RFC */
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 /* server status, or file status */
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 /* hey look, we're getting a file */
00529 int doSTOR(buff)
00530 char *buff;
00531 {
00532    return(recvfile(buff, RECV_FILE));
00533 }
00534 
00535 /* hey, get a file unique */
00536 int doSTOU(buff)
00537 char *buff;
00538 {
00539    return(recvfile(buff, RECV_UNIQ));
00540 }
00541 
00542 /* structure */
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 /* we're UNIX and proud of it! */
00559 int doSYST(buff)
00560 char *buff;
00561 {
00562    printf("215 UNIX Type: L8\r\n");
00563 
00564    return(GOOD);
00565 }
00566 
00567 /* change transfer type */
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;   /* ouch... */
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) { /* Child */
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 /* Same as close if not cmd child started */
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 /* returns -1 = size could not be determined, */
00662 /*          0 = size determined and in filesize */
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 /* see if we need to run a command to convert the file */
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))                 /* file exists can't be a conversion */
00715         if((st.st_mode & S_IFMT) != S_IFREG) {  /* must be regular file */
00716                 printf("550 Not a regular file.\r\n");
00717                 return(CNVT_ERROR);
00718         } else
00719                 return(CNVT_NONE);
00720 
00721    if(errno != ENOENT) {        /* doesn't exist is okay, others are not */
00722         printf(msg550, name, strerror(errno));
00723         return(CNVT_ERROR);
00724    }
00725 
00726    /* find out what kind of conversion */
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                         /* is there a file to convert? */
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 /* oh no, they're taking a file */
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    /* set file position at approriate spot */
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    /* start transfer */
00928    doascii = (type == TYPE_A) ||
00929         ((xmode == SEND_LIST) || (xmode == SEND_NLST)); /* per RFC1123 4.1.2.7 */
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    /* log the received file */
01051    logit("RECV", path(fname));
01052 
01053    /* set file position at approriate spot */
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);    /* per RFC1123 4.1.2.9 */
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    /* start receiving file */
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 /* do file detail */
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,                                     /* file type */
01243         st.st_rdev >> 8,                        /* Major */
01244         st.st_rdev & 0xff,                      /* Minor */
01245         st.st_uid,                              /* UID */
01246         st.st_gid,                              /* GID */
01247         st.st_mode,                             /* File Modes */
01248         st.st_size,                             /* SIZE */
01249         st.st_mtime);                           /* Mod Time */
01250 
01251    return(GOOD);
01252 }

Generated on Fri Apr 14 22:56:53 2006 for minix by  doxygen 1.4.6