ftpd.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2001-2005 by egnite Software GmbH. All rights reserved.
00003  *
00004  * Redistribution and use in source and binary forms, with or without
00005  * modification, are permitted provided that the following conditions
00006  * are met:
00007  *
00008  * 1. Redistributions of source code must retain the above copyright
00009  *    notice, this list of conditions and the following disclaimer.
00010  * 2. Redistributions in binary form must reproduce the above copyright
00011  *    notice, this list of conditions and the following disclaimer in the
00012  *    documentation and/or other materials provided with the distribution.
00013  * 3. Neither the name of the copyright holders nor the names of
00014  *    contributors may be used to endorse or promote products derived
00015  *    from this software without specific prior written permission.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY EGNITE SOFTWARE GMBH AND CONTRIBUTORS
00018  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00019  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00020  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL EGNITE
00021  * SOFTWARE GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00022  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00023  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
00024  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
00025  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
00026  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
00027  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00028  * SUCH DAMAGE.
00029  *
00030  * For additional information see http://www.ethernut.de/
00031  *
00032  */
00033 
00085 #include <sys/version.h>
00086 
00087 #include <sys/socket.h>
00088 #include <netinet/tcp.h>
00089 
00090 #include <string.h>
00091 #include <stdio.h>
00092 #include <stdlib.h>
00093 #include <io.h>
00094 #include <fcntl.h>
00095 #include <sys/stat.h>
00096 #include <dirent.h>
00097 #include <unistd.h>
00098 #include <memdebug.h>
00099 
00100 #include <pro/ftpd.h>
00101 
00102 #ifdef FTPD_DEBUG
00103 #include <sys/heap.h>
00104 #endif
00105 
00112 
00119 
00125 #ifndef FTP_ROOTPATH
00126 #define FTP_ROOTPATH "PNUT:"
00127 #endif
00128 
00134 #ifndef FTP_DATA_PORT
00135 #define FTP_DATA_PORT   20
00136 #endif
00137 
00140 static char *ftp_root;
00141 static char *ftp_user;
00142 static char *ftp_pass;
00143 
00144 /*
00145  * On Harvard architectures constant strings are stored in ROM, 
00146  * because RAM is usually a scarce resource on these platforms.
00147  */
00148 static prog_char cmd_cwd_P[] = "CWD";
00149 static prog_char cmd_dele_P[] = "DELE";
00150 static prog_char cmd_list_P[] = "LIST";
00151 static prog_char cmd_mkd_P[] = "MKD";
00152 static prog_char cmd_xmkd_P[] = "XMKD";
00153 static prog_char cmd_nlst_P[] = "NLST";
00154 static prog_char cmd_noop_P[] = "NOOP";
00155 static prog_char cmd_pass_P[] = "PASS";
00156 static prog_char cmd_pasv_P[] = "PASV";
00157 static prog_char cmd_port_P[] = "PORT";
00158 static prog_char cmd_pwd_P[] = "PWD";
00159 static prog_char cmd_xpwd_P[] = "XPWD";
00160 static prog_char cmd_quit_P[] = "QUIT";
00161 static prog_char cmd_retr_P[] = "RETR";
00162 static prog_char cmd_rmd_P[] = "RMD";
00163 static prog_char cmd_xrmd_P[] = "XRMD";
00164 static prog_char cmd_stor_P[] = "STOR";
00165 static prog_char cmd_syst_P[] = "SYST";
00166 static prog_char cmd_type_P[] = "TYPE";
00167 static prog_char cmd_user_P[] = "USER";
00168 
00169 static char *mon_name = "JanFebMarAprMayJunJulAugSepOctNovDec";
00170 
00171 static prog_char rep_banner[] = "220 Nut/OS FTP %s ready at %.3s%3d %02d:%02d:%02d\r\n";
00172 
00185 static void SplitCmdArg(char * line, char ** cmd, char ** args)
00186 {
00187     /* Skip leading spaces. */
00188     while (*line && *line <= ' ') {
00189         line++;
00190     }
00191 
00192     /* The first word is the command. Convert it to upper case. */
00193     *cmd = line;
00194     while (*line > ' ') {
00195         if (*line >= (uint8_t) 'a' && *line <= (uint8_t) 'z') {
00196             *line -= (uint8_t) 'a' - 'A';
00197         }
00198         line++;
00199     }
00200 
00201     /* Mark end of the command word. */
00202     if (*line) {
00203         *line++ = '\0';
00204     }
00205 
00206     /* Skip spaces. */
00207     while (*line && *line <= ' ') {
00208         ++line;
00209     }
00210 
00211     /* Arguments start here. */
00212     *args = line;
00213     while (*line && *line != '\r' && *line != '\n') {
00214         line++;
00215     }
00216 
00217     /* Mark end of arguments. */
00218     *line = 0;
00219 }
00220 
00236 static int ParseIpPort(CONST char * arg, uint32_t * ip, uint16_t * port)
00237 {
00238     int rc;
00239 
00240     *ip = 0;
00241     *port = 0;
00242     for (rc = 0; rc < 6; rc++) {
00243         if (*arg < '0' || *arg > '9') {
00244             break;
00245         }
00246         if (rc < 4) {
00247             *ip >>= 8;
00248             *ip += atol(arg) << 24;
00249         } else {
00250             *port <<= 8;
00251             *port += atoi(arg);
00252         }
00253         while (*arg && *arg != ',') {
00254             arg++;
00255         }
00256         if (*arg == ',') {
00257             arg++;
00258         }
00259     }
00260     return rc;
00261 }
00262 
00272 int NutFtpRespondOk(FTPSESSION * session, int code)
00273 {
00274     static prog_char fmt_P[] = "%d OK\r\n";
00275 
00276 #ifdef FTPD_DEBUG
00277     printf("\n<'%d OK' ", code);
00278 #endif
00279     fprintf_P(session->ftp_stream, fmt_P, code);
00280     fflush(session->ftp_stream);
00281 
00282     return 0;
00283 }
00284 
00294 int NutFtpRespondBad(FTPSESSION * session, int code)
00295 {
00296     static prog_char fmt_P[] = "%d Failed\r\n";
00297 
00298 #ifdef FTPD_DEBUG
00299     printf("\n<'%d Failed' ", code);
00300 #endif
00301     fprintf_P(session->ftp_stream, fmt_P, code);
00302     fflush(session->ftp_stream);
00303 
00304     return 0;
00305 }
00306 
00316 int NutFtpSendMode(FTPSESSION * session, int binary)
00317 {
00318     static prog_char intro_P[] = "150 Opening ";
00319     static prog_char amode_P[] = "ASCII.\r\n";
00320     static prog_char bmode_P[] = "BINARY.\r\n";
00321 
00322 #ifdef FTPD_DEBUG
00323     printf("\n<'150 Opening %s' ", binary ? "BINARY" : "ASCII");
00324 #endif
00325     fputs_P(intro_P, session->ftp_stream);
00326     fputs_P(binary ? bmode_P : amode_P, session->ftp_stream);
00327     fflush(session->ftp_stream);
00328 
00329     return 0;
00330 }
00331 
00352 char *CreateFullPathName(char *root, char *work, char *path)
00353 {
00354     char *full;
00355     char *cp;
00356     size_t rl = root ? strlen(root) : 0;
00357     size_t wl = work ? strlen(work) : 0;
00358     size_t pl = path ? strlen(path) : 0;
00359 
00360     /* Ignore trailing slashes in root and work. */
00361     if (rl && *(root + rl - 1) == '/') {
00362         rl--;
00363     }
00364     if (wl && *(work + wl - 1) == '/') {
00365         wl--;
00366     }
00367 
00368     if ((full = malloc(rl + wl + pl + 3)) != NULL) {
00369         /* Put the root in front. */
00370         cp = full;
00371         if (rl) {
00372             cp = strcpy(full, root) + rl;
00373         }
00374 
00375         /* If path is relative, prepend the working directory. */
00376         if(pl == 0 || *path != '/') {
00377             if (wl) {
00378                 if (*work != '/') {
00379                     *cp++ = '/';
00380                 }
00381                 cp = strcpy(cp, work) + wl;
00382             }
00383             *cp++ = '/';
00384             rl++;
00385         }
00386 
00387         if (pl) {
00388             *cp = 0;
00389             work = full + rl;
00390 
00391             while (*path) {
00392                 /* Ingore duplicate slashes. */
00393                 if (*path == '/') {
00394                     *cp++ = *path++;
00395                     while (*path == '/') {
00396                         path++;
00397                     }
00398                 }
00399                 /* Ignore single dots. */
00400                 if (*path == '.') {
00401                     path++;
00402                     if (*path == '/') {
00403                         path++;
00404                         continue;
00405                     }
00406                     if (*path == 0) {
00407                         break;
00408                     }
00409                     if (*path == '.') {
00410                         path++;
00411                         if (*path == '/' || *path == 0) {
00412                             if (cp != work) {
00413                                 cp--;
00414                                 while (cp != work) {
00415                                     cp--;
00416                                     if (*cp == '/') {
00417                                         break;
00418                                     }
00419                                 }
00420                             }
00421                             continue;
00422                         }
00423                         path--;
00424                     }
00425                     path--;
00426                 }
00427                 /* Copy the current path component. */
00428                 while (*path && *path != '/') {
00429                     *cp++ = *path++;
00430                 }
00431             }
00432         }
00433         *cp = 0;
00434     }
00435     return full;
00436 }
00437 
00447 TCPSOCKET *NutFtpDataConnect(FTPSESSION * session)
00448 {
00449     TCPSOCKET *sock;
00450     int rc;
00451 
00452     if ((sock = NutTcpCreateSocket()) != 0) {
00453 
00454         if (session->ftp_maxseg) {
00455             NutTcpSetSockOpt(sock, TCP_MAXSEG, &session->ftp_maxseg, sizeof(session->ftp_maxseg));
00456         }
00457         if (session->ftp_passive) {
00458             rc = NutTcpAccept(sock, session->ftp_data_port);
00459         } else {
00460             rc = NutTcpConnect(sock, session->ftp_data_ip, session->ftp_data_port);
00461         }
00462         if (rc) {
00463             NutTcpCloseSocket(sock);
00464             sock = 0;
00465         }
00466     }
00467     return sock;
00468 }
00469 
00483 int NutRegisterFtpRoot(CONST char *path)
00484 {
00485     /* Reset path to default. */
00486     if (path == NULL || *path == 0) {
00487         /* Release previously allocate space. */
00488         if (ftp_root) {
00489             free(ftp_root);
00490         }
00491         if ((ftp_root = malloc(sizeof(FTP_ROOTPATH))) == 0) {
00492             return -1;
00493         }
00494         strcpy(ftp_root, FTP_ROOTPATH);
00495     }
00496 
00497     /* Set a specified path. */
00498     else {
00499         char *cp = strchr(path, ':');
00500         int len = strlen(path);
00501 
00502         /* Make sure that the path fulfills all requirements. */
00503         if (len < 2 || cp == 0 || (*++cp && *cp != '/')) {
00504             return -1;
00505         }
00506 
00507         /* Allocate space for new path, but preserve the current one. */
00508         if ((cp = malloc(len + 1)) == 0) {
00509             return -1;
00510         }
00511 
00512         /* Take over, releasing previously allocate space. */
00513         strcpy(cp, path);
00514         if (ftp_root) {
00515             free(ftp_root);
00516         }
00517         ftp_root = cp;
00518 
00519         /* Chop off an optional trailing slash. */
00520         cp = cp + strlen(cp) - 1;
00521         if (*cp == '/') {
00522             *cp = 0;
00523         }
00524     }
00525     return 0;
00526 }
00527 
00543 int NutRegisterFtpUser(CONST char *user, CONST char *pass)
00544 {
00545     if (ftp_user) {
00546         free(ftp_user);
00547         ftp_user = NULL;
00548     }
00549     if (user && *user) {
00550         if ((ftp_user = strdup(user)) == NULL) {
00551             return -1;
00552         }
00553     }
00554     if (ftp_pass) {
00555         free(ftp_pass);
00556         ftp_pass = NULL;
00557     }
00558     if (pass && *pass) {
00559         if ((ftp_pass = strdup(pass)) == NULL) {
00560             return -1;
00561         }
00562     }
00563     return 0;
00564 }
00565 
00566 
00576 FTPSESSION *NutFtpOpenSession(TCPSOCKET * sock)
00577 {
00578     FTPSESSION *session;
00579 
00580     session = malloc(sizeof(FTPSESSION));
00581 
00582     if (session) {
00583         memset(session, 0, sizeof(FTPSESSION));
00584         session->ftp_data_port = FTP_DATA_PORT;
00585         session->ftp_maxseg = sock->so_mss;
00586         session->ftp_sock = sock;
00587 
00588         /* Set initial working directory. */
00589         if ((session->ftp_cwd = malloc(2)) == 0) {
00590             free(session);
00591             session = 0;
00592         } else {
00593             session->ftp_cwd[0] = '/';
00594             session->ftp_cwd[1] = 0;
00595 
00596             /*
00597              * Open a stream and associate it with the socket, so 
00598              * we can use standard I/O. Note, that socket streams
00599              * currently do support text mode.
00600              */
00601             if ((session->ftp_stream = _fdopen((int) sock, "r+b")) == 0) {
00602                 free(session->ftp_cwd);
00603                 free(session);
00604                 session = 0;
00605             }
00606         }
00607     }
00608     return session;
00609 }
00610 
00617 void NutFtpCloseSession(FTPSESSION * session)
00618 {
00619     if (session) {
00620         /* Close the stream. */
00621         fclose(session->ftp_stream);
00622         if (session->ftp_cwd) {
00623             free(session->ftp_cwd);
00624         }
00625         free(session);
00626     }
00627 }
00628 
00639 int NutFtpProcessCwd(FTPSESSION * session, char *path)
00640 {
00641     struct stat st;
00642     char *cp = path + strlen(ftp_root);
00643 
00644     if (*cp && strcmp(cp, "/")) {
00645         /*
00646          * Check, if the path exists and if this is a directory. 
00647          */
00648         if (stat(path, &st) || !S_ISDIR(st.st_mode)) {
00649             return NutFtpRespondBad(session, 550);
00650         }
00651     }
00652 
00653     /*
00654      * Store the new working directory excluding our root part.
00655      */
00656     if (*cp == 0) {
00657         cp = "/";
00658     }
00659     if (session->ftp_cwd) {
00660         free(session->ftp_cwd);
00661     }
00662     if ((session->ftp_cwd = strdup(cp)) == NULL) {
00663         return NutFtpRespondBad(session, 550);
00664     }
00665     return NutFtpRespondOk(session, 250);
00666 }
00667 
00680 int NutFtpProcessDelete(FTPSESSION * session, char *path)
00681 {
00682     if (unlink(path)) {
00683         return NutFtpRespondBad(session, 550);
00684     }
00685     return NutFtpRespondOk(session, 250);
00686 }
00687 
00705 int NutFtpTransferFile(FTPSESSION * session, char *path, int mode)
00706 {
00707     TCPSOCKET *sock;
00708     int ec = 550;
00709     int fh;
00710 
00711     /* Open the file to send. */
00712     if (mode) {
00713         fh = _open(path, _O_BINARY | _O_RDONLY);
00714     }
00715     /* Open the file to receive. */
00716     else {
00717         fh = _open(path, _O_CREAT | _O_TRUNC);
00718     }
00719 
00720     if (fh != -1) {
00721         /* File status OK, opening data connection */
00722         NutFtpSendMode(session, session->ftp_tran_mode);
00723         if ((sock = NutFtpDataConnect(session)) != 0) {
00724             uint16_t mss = sock->so_mss;
00725             uint8_t *buf;
00726 
00727             if (mss < 256) {
00728                 mss = 256;
00729             }
00730             if ((buf = malloc(mss)) != 0) {
00731                 int got;
00732 
00733                 ec = 0;
00734 
00735                 /* Send a file. */
00736                 if (mode) {
00737                     while ((got = _read(fh, buf, mss)) > 0) {
00738                         if (NutTcpSend(sock, buf, got) != got) {
00739                             ec = 551;
00740                             break;
00741                         }
00742                     }
00743                 }
00744 
00745                 /* Receive a file. */
00746                 else {
00747                     while ((got = NutTcpReceive(sock, buf, mss)) > 0) {
00748                         int x;
00749                         if ((x = _write(fh, buf, got)) != got) {
00750                             ec = 552;
00751                             break;
00752                         }
00753                     }
00754                 }
00755                 free(buf);
00756             }
00757             NutTcpCloseSocket(sock);
00758         }
00759         _close(fh);
00760 
00761         /* Remove files received with an error. */
00762         if (mode == 0 && ec) {
00763             unlink(path);
00764         }
00765     }
00766     if (ec) {
00767         return NutFtpRespondBad(session, ec);
00768     }
00769     return NutFtpRespondOk(session, 226);
00770 }
00771 
00784 int NutFtpTransferDirectory(FTPSESSION * session, char *path)
00785 {
00786     TCPSOCKET *sock;
00787     FILE *fp;
00788 
00789     struct stat st;
00790     DIR *dir;
00791     struct dirent *d_ent;
00792     tm *gmt;
00793     uint32_t size;
00794     int ec = 550;
00795     char *name;
00796 
00797     dir = opendir(path);
00798     if (dir) {
00799         NutFtpSendMode(session, 0);
00800         if ((sock = NutFtpDataConnect(session)) != 0) {
00801             if ((fp = _fdopen((int) sock, "r+b")) != 0) {
00802                 ec = 0;
00803                 while ((d_ent = readdir(dir)) != 0) {
00804                     if (d_ent->d_name[0] == '.') {
00805                         continue;
00806                     }
00807 
00808                     if ((name = malloc(strlen(path) + strlen(d_ent->d_name) + 2)) != 0) {
00809                         sprintf(name, "%s/%s", path, d_ent->d_name);
00810                         if (stat(name, &st) == 0) {
00811                             if (S_ISDIR(st.st_mode)) {
00812                                 fputc('d', fp);
00813                                 size = 0;
00814                             } else {
00815                                 fputc('-', fp);
00816                                 size = st.st_size;
00817                             }
00818                             fprintf(fp, "rw-rw-rw-  1 0 0 %6lu ", size);
00819                             gmt = gmtime(&st.st_mtime);
00820                             //fprintf(fp, "%s %u %u ", mon_name[gmt->tm_mon], gmt->tm_mday, 1900 + gmt->tm_year);
00821                             fprintf(fp, "%.3s %u ", mon_name + gmt->tm_mon * 3, gmt->tm_mday);
00822                             //fprintf(fp, "%02u:%02u:%02u ", gmt->tm_hour, gmt->tm_min, gmt->tm_sec);
00823                             fprintf(fp, "%02u:%02u ", gmt->tm_hour, gmt->tm_min);
00824                             fputs(d_ent->d_name, fp);
00825                             fputs("\r\n", fp);
00826                         }
00827                         free(name);
00828                     }
00829                 }
00830                 fclose(fp);
00831             }
00832             NutTcpCloseSocket(sock);
00833         }
00834         closedir(dir);
00835     }
00836     if (ec) {
00837         return NutFtpRespondBad(session, ec);
00838     }
00839     return NutFtpRespondOk(session, 226);
00840 }
00841 
00854 int NutFtpProcessMkd(FTPSESSION * session, char *path)
00855 {
00856     if (mkdir(path, 0777)) {
00857         return NutFtpRespondBad(session, 550);
00858     }
00859     return NutFtpRespondOk(session, 257);
00860 }
00861 
00874 int NutFtpProcessPass(FTPSESSION * session, char *pass)
00875 {
00876     if (ftp_pass && *ftp_pass) {
00877         if (session->ftp_login != 1 || strcmp(ftp_pass, pass)) {
00878             session->ftp_login = 0;
00879             return NutFtpRespondBad(session, 550);
00880         }
00881     }
00882     session->ftp_login = 2;
00883     return NutFtpRespondOk(session, 230);
00884 }
00885 
00899 int NutFtpProcessPassiv(FTPSESSION * session)
00900 {
00901     uint32_t ip = session->ftp_sock->so_local_addr;
00902     uint16_t port = 20;
00903 
00904     fprintf(session->ftp_stream, "227 Passive (%u,%u,%u,%u,%u,%u).\r\n",        /* */
00905             (uint8_t) ip, (uint8_t) (ip >> 8), (uint8_t) (ip >> 16), (uint8_t) (ip >> 24),  /* */
00906             (uint8_t) (port >> 8), (uint8_t) port);
00907     fflush(session->ftp_stream);
00908     session->ftp_passive = 1;
00909 
00910     return 0;
00911 }
00912 
00927 int NutFtpProcessPort(FTPSESSION * session, char *args)
00928 {
00929     if (ParseIpPort(args, &session->ftp_data_ip, &session->ftp_data_port) == 6) {
00930         if (session->ftp_sock->so_remote_addr == session->ftp_data_ip) {
00931             return NutFtpRespondOk(session, 200);
00932         }
00933         return NutFtpRespondBad(session, 425);
00934     }
00935     return NutFtpRespondBad(session, 501);;
00936 }
00937 
00950 int NutFtpProcessPwd(FTPSESSION * session)
00951 {
00952 #ifdef FTPD_DEBUG
00953     printf("\n<'257 \"%s\"' ", session->ftp_cwd);
00954 #endif
00955     fprintf(session->ftp_stream, "257 \"%s\"\r\n", session->ftp_cwd);
00956     return 0;
00957 }
00958 
00971 int NutFtpProcessRmd(FTPSESSION * session, char *path)
00972 {
00973     if (rmdir(path)) {
00974         return NutFtpRespondBad(session, 451);
00975     }
00976     return NutFtpRespondOk(session, 257);
00977 }
00978 
00988 int NutFtpProcessSystem(FTPSESSION * session)
00989 {
00990 #ifdef FTPD_DEBUG
00991     printf("\n<'215 UNIX Type: L8' ");
00992 #endif
00993     fputs("215 UNIX Type: L8\r\n", session->ftp_stream);
00994     return 0;
00995 }
00996 
01011 int NutFtpProcessType(FTPSESSION * session, char *typecode)
01012 {
01013     session->ftp_tran_mode = (*typecode != 'A') && (*typecode != 'a');
01014     return NutFtpRespondOk(session, 200);
01015 }
01016 
01029 int NutFtpProcessUser(FTPSESSION * session, char *user)
01030 {
01031     if (ftp_user && *ftp_user) {
01032         if (session->ftp_login && strcmp(ftp_user, user)) {
01033             session->ftp_login = 0;
01034             return NutFtpRespondBad(session, 550);
01035         }
01036     }
01037 
01038     /* Need a password too. */
01039     if (ftp_pass && *ftp_pass) {
01040         session->ftp_login = 1;
01041         return NutFtpRespondOk(session, 331);
01042     }
01043 
01044     /* No password required. */
01045     session->ftp_login = 2;
01046     return NutFtpRespondOk(session, 230);
01047 }
01048 
01060 int NutFtpProcessRequest(FTPSESSION * session, char *request)
01061 {
01062     int rc = 0;
01063     char *cmd;
01064     char *args;
01065 
01066     /* Split the line into command and argument part. */
01067     SplitCmdArg(request, &cmd, &args);
01068 #ifdef FTPD_DEBUG
01069     printf("\n>'%s %s' ", cmd, args);
01070 #endif
01071 
01072     /* QUIT - Terminate session. */
01073     if (strcmp_P(cmd, cmd_quit_P) == 0) {
01074         NutFtpRespondOk(session, 221);
01075         rc = -1;
01076     }
01077 
01078     /* USER <username> - Check user name. */
01079     else if (strcmp_P(cmd, cmd_user_P) == 0) {
01080         rc = NutFtpProcessUser(session, args);
01081     }
01082 
01083     /* PASS <password> - Check user password. */
01084     else if (strcmp_P(cmd, cmd_pass_P) == 0) {
01085         rc = NutFtpProcessPass(session, args);
01086     } else if (strcmp_P(cmd, cmd_noop_P) == 0) {
01087         NutFtpRespondOk(session, 200);
01088     }
01089     /* Anything else requires a successful login. */
01090     else if (session->ftp_login < 2) {
01091         rc = NutFtpRespondBad(session, 530);
01092     }
01093 
01094     /* Valid login. */
01095     else {
01096 
01097         /* PASV - Prepare passive transfer. */
01098         if (strcmp_P(cmd, cmd_pasv_P) == 0) {
01099             rc = NutFtpProcessPassiv(session);
01100         }
01101 
01102         /* PORT <host-port> - Set data connection. */
01103         else if (strcmp_P(cmd, cmd_port_P) == 0) {
01104             rc = NutFtpProcessPort(session, args);
01105         }
01106 
01107         /* [X]PWD - Send name of current working directory. */
01108         else if (strcmp_P(cmd, cmd_pwd_P) == 0 || strcmp_P(cmd, cmd_xpwd_P) == 0) {
01109             rc = NutFtpProcessPwd(session);
01110         }
01111 
01112         /* SYST - Send system identifier. */
01113         else if (strcmp_P(cmd, cmd_syst_P) == 0) {
01114             rc = NutFtpProcessSystem(session);
01115         }
01116 
01117         /* TYPE <type-code> - Receive transfer mode. */
01118         else if (strcmp_P(cmd, cmd_type_P) == 0) {
01119             rc = NutFtpProcessType(session, args);
01120         }
01121 
01122         /* Commands with path name argument. */
01123         else {
01124             char *path;
01125 
01126             if ((path = CreateFullPathName(ftp_root, session->ftp_cwd, args)) == 0) {
01127                 rc = NutFtpRespondBad(session, 451);
01128             }
01129 
01130             /* CWD <pathname> - Change working directory. */
01131             else if (strcmp_P(cmd, cmd_cwd_P) == 0) {
01132                 rc = NutFtpProcessCwd(session, path);
01133             }
01134 
01135             /* DELE <pathname> - Delete a file. */
01136             else if (strcmp_P(cmd, cmd_dele_P) == 0) {
01137                 rc = NutFtpProcessDelete(session, path);
01138             }
01139 
01140             /* LIST | NLST [<pathname>] - Send list of files in a directory. */
01141             else if (strcmp_P(cmd, cmd_list_P) == 0 || strcmp_P(cmd, cmd_nlst_P) == 0) {
01142                 rc = NutFtpTransferDirectory(session, path);
01143             }
01144 
01145             /* MKD <pathname> - Make a directory. */
01146             else if (strcmp_P(cmd, cmd_mkd_P) == 0 || strcmp_P(cmd, cmd_xmkd_P) == 0) {
01147                 rc = NutFtpProcessMkd(session, path);
01148             }
01149 
01150             /* RETR <pathname> - Send a file to the client. */
01151             else if (strcmp_P(cmd, cmd_retr_P) == 0) {
01152                 rc = NutFtpTransferFile(session, path, 1);
01153             }
01154 
01155             /* RMD <pathname> - Remove a directory. */
01156             else if (strcmp_P(cmd, cmd_rmd_P) == 0 || strcmp_P(cmd, cmd_xrmd_P) == 0) {
01157                 rc = NutFtpProcessRmd(session, path);
01158             }
01159 
01160             /* STOR <pathname> - Receive a file from the client. */
01161             else if (strcmp_P(cmd, cmd_stor_P) == 0) {
01162                 rc = NutFtpTransferFile(session, path, 0);
01163             }
01164 
01165             /* Anything else is an unknown command. */
01166             else {
01167                 rc = NutFtpRespondBad(session, 502);
01168             }
01169 
01170             if (path) {
01171                 free(path);
01172             }
01173         }
01174     }
01175     return rc;
01176 }
01177 
01193 int NutFtpServerSession(TCPSOCKET * sock)
01194 {
01195     int rc = 0;
01196     FTPSESSION *session;
01197     char *buff;
01198     time_t now;
01199     struct _tm *tip;
01200     char ch;
01201 
01202     /* Set the root path if not yet done. */
01203     if (NutRegisterFtpRoot(ftp_root)) {
01204         return -1;
01205     }
01206 
01207     /* Allocate the command line buffer. */
01208     if ((buff = malloc(FTP_MAX_CMDBUF)) == 0) {
01209         return -1;
01210     }
01211 
01212     /* Create a session structure and open a stream. */
01213     if ((session = NutFtpOpenSession(sock)) == 0) {
01214         free(buff);
01215         return -1;
01216     }
01217 
01218     /* Send a welcome banner including system time. */
01219     time(&now);
01220     tip = localtime(&now);
01221 #ifdef FTPD_DEBUG
01222     printf("\n<'");
01223     printf_P(rep_banner, NutVersionString(), &mon_name[tip->tm_mon * 3],        /* */
01224              tip->tm_mday, tip->tm_hour, tip->tm_min, tip->tm_sec);
01225 #endif
01226     fprintf_P(session->ftp_stream, rep_banner, NutVersionString(),      /* */
01227               &mon_name[tip->tm_mon * 3],       /* */
01228               tip->tm_mday, tip->tm_hour, tip->tm_min, tip->tm_sec);
01229 
01230     /* 
01231      * Loop for requests. 
01232      */
01233     while (rc == 0) {
01234 
01235         /* Flush any previous output and read a new command line. */
01236         fflush(session->ftp_stream);
01237         if (fgets(buff, FTP_MAX_CMDBUF, session->ftp_stream) == 0) {
01238             rc = -1;
01239             break;
01240         }
01241 
01242         /* Skip command lines, which are too long. */
01243         if ((ch = *(buff + strlen(buff) - 1)) != '\n' && ch != '\r') {
01244             do {
01245                 if (fgets(buff, FTP_MAX_CMDBUF, session->ftp_stream) == 0) {
01246                     rc = -1;
01247                     break;
01248                 }
01249             } while ((ch = *(buff + strlen(buff) - 1)) != '\n' && ch != '\r');
01250             if (rc == 0) {
01251                 rc = NutFtpRespondBad(session, 500);
01252             }
01253         }
01254 
01255         /* Process the request. */
01256         else {
01257             rc = NutFtpProcessRequest(session, buff);
01258         }
01259     }
01260 
01261     /* Cleanup and return. */
01262     NutFtpCloseSession(session);
01263     free(buff);
01264     return rc;
01265 }
01266 

© 2000-2007 by egnite Software GmbH - visit http://www.ethernut.de/