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 
00071 #include <sys/version.h>
00072 
00073 #include <sys/socket.h>
00074 #include <netinet/tcp.h>
00075 
00076 #include <string.h>
00077 #include <stdio.h>
00078 #include <stdlib.h>
00079 #include <io.h>
00080 #include <fcntl.h>
00081 #include <sys/stat.h>
00082 #include <dirent.h>
00083 #include <unistd.h>
00084 
00085 #include <pro/ftpd.h>
00086 
00087 #ifdef FTPD_DEBUG
00088 #include <sys/heap.h>
00089 #endif
00090 
00097 
00104 
00110 #ifndef FTP_ROOTPATH
00111 #define FTP_ROOTPATH "PNUT:"
00112 #endif
00113 
00119 #ifndef FTP_DATA_PORT
00120 #define FTP_DATA_PORT   20
00121 #endif
00122 
00125 static char *ftp_root;
00126 static char *ftp_user;
00127 static char *ftp_pass;
00128 
00129 /*
00130  * On Harvard architectures constant strings are stored in ROM, 
00131  * because RAM is usually a scarce resource on these platforms.
00132  */
00133 static prog_char cmd_cwd_P[] = "CWD";
00134 static prog_char cmd_dele_P[] = "DELE";
00135 static prog_char cmd_list_P[] = "LIST";
00136 static prog_char cmd_mkd_P[] = "MKD";
00137 static prog_char cmd_xmkd_P[] = "XMKD";
00138 static prog_char cmd_nlst_P[] = "NLST";
00139 static prog_char cmd_noop_P[] = "NOOP";
00140 static prog_char cmd_pass_P[] = "PASS";
00141 static prog_char cmd_pasv_P[] = "PASV";
00142 static prog_char cmd_port_P[] = "PORT";
00143 static prog_char cmd_pwd_P[] = "PWD";
00144 static prog_char cmd_xpwd_P[] = "XPWD";
00145 static prog_char cmd_quit_P[] = "QUIT";
00146 static prog_char cmd_retr_P[] = "RETR";
00147 static prog_char cmd_rmd_P[] = "RMD";
00148 static prog_char cmd_xrmd_P[] = "XRMD";
00149 static prog_char cmd_stor_P[] = "STOR";
00150 static prog_char cmd_syst_P[] = "SYST";
00151 static prog_char cmd_type_P[] = "TYPE";
00152 static prog_char cmd_user_P[] = "USER";
00153 
00154 static char *mon_name = "JanFebMarAprMayJunJulAugSepOctNovDec";
00155 
00156 static prog_char rep_banner[] = "220 Nut/OS FTP %s ready at %.3s%3d %02d:%02d:%02d\r\n";
00157 
00170 static void SplitCmdArg(char * line, char ** cmd, char ** args)
00171 {
00172     /* Skip leading spaces. */
00173     while (*line && *line <= ' ') {
00174         line++;
00175     }
00176 
00177     /* The first word is the command. Convert it to upper case. */
00178     *cmd = line;
00179     while (*line > ' ') {
00180         if (*line >= (u_char) 'a' && *line <= (u_char) 'z') {
00181             *line -= (u_char) 'a' - 'A';
00182         }
00183         line++;
00184     }
00185 
00186     /* Mark end of the command word. */
00187     if (*line) {
00188         *line++ = '\0';
00189     }
00190 
00191     /* Skip spaces. */
00192     while (*line && *line <= ' ') {
00193         ++line;
00194     }
00195 
00196     /* Arguments start here. */
00197     *args = line;
00198     while (*line && *line != '\r' && *line != '\n') {
00199         line++;
00200     }
00201 
00202     /* Mark end of arguments. */
00203     *line = 0;
00204 }
00205 
00221 static int ParseIpPort(CONST char * arg, u_long * ip, u_short * port)
00222 {
00223     int rc;
00224 
00225     *ip = 0;
00226     *port = 0;
00227     for (rc = 0; rc < 6; rc++) {
00228         if (*arg < '0' || *arg > '9') {
00229             break;
00230         }
00231         if (rc < 4) {
00232             *ip >>= 8;
00233             *ip += atol(arg) << 24;
00234         } else {
00235             *port <<= 8;
00236             *port += atoi(arg);
00237         }
00238         while (*arg && *arg != ',') {
00239             arg++;
00240         }
00241         if (*arg == ',') {
00242             arg++;
00243         }
00244     }
00245     return rc;
00246 }
00247 
00257 int NutFtpRespondOk(FTPSESSION * session, int code)
00258 {
00259     static prog_char fmt_P[] = "%d OK\r\n";
00260 
00261 #ifdef FTPD_DEBUG
00262     printf("\n<'%d OK' ", code);
00263 #endif
00264     fprintf_P(session->ftp_stream, fmt_P, code);
00265     fflush(session->ftp_stream);
00266 
00267     return 0;
00268 }
00269 
00279 int NutFtpRespondBad(FTPSESSION * session, int code)
00280 {
00281     static prog_char fmt_P[] = "%d Failed\r\n";
00282 
00283 #ifdef FTPD_DEBUG
00284     printf("\n<'%d Failed' ", code);
00285 #endif
00286     fprintf_P(session->ftp_stream, fmt_P, code);
00287     fflush(session->ftp_stream);
00288 
00289     return 0;
00290 }
00291 
00301 int NutFtpSendMode(FTPSESSION * session, int binary)
00302 {
00303     static prog_char intro_P[] = "150 Opening ";
00304     static prog_char amode_P[] = "ASCII.\r\n";
00305     static prog_char bmode_P[] = "BINARY.\r\n";
00306 
00307 #ifdef FTPD_DEBUG
00308     printf("\n<'150 Opening %s' ", binary ? "BINARY" : "ASCII");
00309 #endif
00310     fputs_P(intro_P, session->ftp_stream);
00311     fputs_P(binary ? bmode_P : amode_P, session->ftp_stream);
00312     fflush(session->ftp_stream);
00313 
00314     return 0;
00315 }
00316 
00337 char *CreateFullPathName(char *root, char *work, char *path)
00338 {
00339     char *full;
00340     char *cp;
00341     size_t rl = root ? strlen(root) : 0;
00342     size_t wl = work ? strlen(work) : 0;
00343     size_t pl = path ? strlen(path) : 0;
00344 
00345     /* Ignore trailing slashes in root and work. */
00346     if (rl && *(root + rl - 1) == '/') {
00347         rl--;
00348     }
00349     if (wl && *(work + wl - 1) == '/') {
00350         wl--;
00351     }
00352 
00353     if ((full = malloc(rl + wl + pl + 3)) != NULL) {
00354         /* Put the root in front. */
00355         cp = full;
00356         if (rl) {
00357             cp = strcpy(full, root) + rl;
00358         }
00359 
00360         /* If path is relative, prepend the working directory. */
00361         if(pl == 0 || *path != '/') {
00362             if (wl) {
00363                 if (*work != '/') {
00364                     *cp++ = '/';
00365                 }
00366                 cp = strcpy(cp, work) + wl;
00367             }
00368             *cp++ = '/';
00369             rl++;
00370         }
00371 
00372         if (pl) {
00373             *cp = 0;
00374             work = full + rl;
00375 
00376             while (*path) {
00377                 /* Ingore duplicate slashes. */
00378                 if (*path == '/') {
00379                     *cp++ = *path++;
00380                     while (*path == '/') {
00381                         path++;
00382                     }
00383                 }
00384                 /* Ignore single dots. */
00385                 if (*path == '.') {
00386                     path++;
00387                     if (*path == '/') {
00388                         path++;
00389                         continue;
00390                     }
00391                     if (*path == 0) {
00392                         break;
00393                     }
00394                     if (*path == '.') {
00395                         path++;
00396                         if (*path == '/' || *path == 0) {
00397                             if (cp != work) {
00398                                 cp--;
00399                                 while (cp != work) {
00400                                     cp--;
00401                                     if (*cp == '/') {
00402                                         break;
00403                                     }
00404                                 }
00405                             }
00406                             continue;
00407                         }
00408                         path--;
00409                     }
00410                     path--;
00411                 }
00412                 /* Copy the current path component. */
00413                 while (*path && *path != '/') {
00414                     *cp++ = *path++;
00415                 }
00416             }
00417         }
00418         *cp = 0;
00419     }
00420     return full;
00421 }
00422 
00432 TCPSOCKET *NutFtpDataConnect(FTPSESSION * session)
00433 {
00434     TCPSOCKET *sock;
00435     int rc;
00436 
00437     if ((sock = NutTcpCreateSocket()) != 0) {
00438 
00439         if (session->ftp_maxseg) {
00440             NutTcpSetSockOpt(sock, TCP_MAXSEG, &session->ftp_maxseg, sizeof(session->ftp_maxseg));
00441         }
00442         if (session->ftp_passive) {
00443             rc = NutTcpAccept(sock, session->ftp_data_port);
00444         } else {
00445             rc = NutTcpConnect(sock, session->ftp_data_ip, session->ftp_data_port);
00446         }
00447         if (rc) {
00448             NutTcpCloseSocket(sock);
00449             sock = 0;
00450         }
00451     }
00452     return sock;
00453 }
00454 
00468 int NutRegisterFtpRoot(CONST char *path)
00469 {
00470     /* Reset path to default. */
00471     if (path == NULL || *path == 0) {
00472         /* Release previously allocate space. */
00473         if (ftp_root) {
00474             free(ftp_root);
00475         }
00476         if ((ftp_root = malloc(sizeof(FTP_ROOTPATH))) == 0) {
00477             return -1;
00478         }
00479         strcpy(ftp_root, FTP_ROOTPATH);
00480     }
00481 
00482     /* Set a specified path. */
00483     else {
00484         char *cp = strchr(path, ':');
00485         int len = strlen(path);
00486 
00487         /* Make sure that the path fulfills all requirements. */
00488         if (len < 2 || cp == 0 || (*++cp && *cp != '/')) {
00489             return -1;
00490         }
00491 
00492         /* Allocate space for new path, but preserve the current one. */
00493         if ((cp = malloc(len + 1)) == 0) {
00494             return -1;
00495         }
00496 
00497         /* Take over, releasing previously allocate space. */
00498         strcpy(cp, path);
00499         if (ftp_root) {
00500             free(ftp_root);
00501         }
00502         ftp_root = cp;
00503 
00504         /* Chop off an optional trailing slash. */
00505         cp = cp + strlen(cp) - 1;
00506         if (*cp == '/') {
00507             *cp = 0;
00508         }
00509     }
00510     return 0;
00511 }
00512 
00528 int NutRegisterFtpUser(CONST char *user, CONST char *pass)
00529 {
00530     if (ftp_user) {
00531         free(ftp_user);
00532         ftp_user = 0;
00533     }
00534     if (user && *user) {
00535         if ((ftp_user = malloc(strlen(user) + 1)) == 0) {
00536             return -1;
00537         }
00538         strcpy(ftp_user, user);
00539     }
00540     if (ftp_pass) {
00541         free(ftp_pass);
00542         ftp_pass = 0;
00543     }
00544     if (pass && *pass) {
00545         if ((ftp_pass = malloc(strlen(pass) + 1)) == 0) {
00546             return -1;
00547         }
00548         strcpy(ftp_pass, pass);
00549     }
00550     return 0;
00551 }
00552 
00553 
00563 FTPSESSION *NutFtpOpenSession(TCPSOCKET * sock)
00564 {
00565     FTPSESSION *session;
00566 
00567     session = malloc(sizeof(FTPSESSION));
00568 
00569     if (session) {
00570         memset(session, 0, sizeof(FTPSESSION));
00571         session->ftp_data_port = FTP_DATA_PORT;
00572         session->ftp_maxseg = sock->so_mss;
00573         session->ftp_sock = sock;
00574 
00575         /* Set initial working directory. */
00576         if ((session->ftp_cwd = malloc(2)) == 0) {
00577             free(session);
00578             session = 0;
00579         } else {
00580             session->ftp_cwd[0] = '/';
00581             session->ftp_cwd[1] = 0;
00582 
00583             /*
00584              * Open a stream and associate it with the socket, so 
00585              * we can use standard I/O. Note, that socket streams
00586              * currently do support text mode.
00587              */
00588             if ((session->ftp_stream = _fdopen((int) sock, "r+b")) == 0) {
00589                 free(session->ftp_cwd);
00590                 free(session);
00591                 session = 0;
00592             }
00593         }
00594     }
00595     return session;
00596 }
00597 
00604 void NutFtpCloseSession(FTPSESSION * session)
00605 {
00606     if (session) {
00607         /* Close the stream. */
00608         fclose(session->ftp_stream);
00609         if (session->ftp_cwd) {
00610             free(session->ftp_cwd);
00611         }
00612         free(session);
00613     }
00614 }
00615 
00626 int NutFtpProcessCwd(FTPSESSION * session, char *path)
00627 {
00628     struct stat st;
00629     char *cp = path + strlen(ftp_root);
00630 
00631     if (*cp && strcmp(cp, "/")) {
00632         /*
00633          * Check, if the path exists and if this is a directory. 
00634          */
00635         if (stat(path, &st) || st.st_mode == 0) {
00636             return NutFtpRespondBad(session, 550);
00637         }
00638     }
00639 
00640     /*
00641      * Store the new working directory excluding our root part.
00642      */
00643     if (*cp == 0) {
00644         cp = "/";
00645     }
00646     if (session->ftp_cwd) {
00647         free(session->ftp_cwd);
00648     }
00649     if ((session->ftp_cwd = malloc(strlen(cp) + 1)) == 0) {
00650         return NutFtpRespondBad(session, 550);
00651     }
00652     strcpy(session->ftp_cwd, cp);
00653 
00654     return NutFtpRespondOk(session, 250);
00655 }
00656 
00669 int NutFtpProcessDelete(FTPSESSION * session, char *path)
00670 {
00671     if (unlink(path)) {
00672         return NutFtpRespondBad(session, 550);
00673     }
00674     return NutFtpRespondOk(session, 250);
00675 }
00676 
00694 int NutFtpTransferFile(FTPSESSION * session, char *path, int mode)
00695 {
00696     TCPSOCKET *sock;
00697     int ec = 550;
00698     int fh;
00699 
00700     /* Open the file to send. */
00701     if (mode) {
00702         fh = _open(path, _O_BINARY | _O_RDONLY);
00703     }
00704     /* Open the file to receive. */
00705     else {
00706         fh = _open(path, _O_CREAT | _O_TRUNC);
00707     }
00708 
00709     if (fh != -1) {
00710         /* File status OK, opening data connection */
00711         NutFtpSendMode(session, session->ftp_tran_mode);
00712         if ((sock = NutFtpDataConnect(session)) != 0) {
00713             u_short mss = sock->so_mss;
00714             u_char *buf;
00715 
00716             if (mss < 256) {
00717                 mss = 256;
00718             }
00719             if ((buf = malloc(mss)) != 0) {
00720                 int got;
00721 
00722                 ec = 0;
00723 
00724                 /* Send a file. */
00725                 if (mode) {
00726                     while ((got = _read(fh, buf, mss)) > 0) {
00727                         if (NutTcpSend(sock, buf, got) != got) {
00728                             ec = 551;
00729                             break;
00730                         }
00731                     }
00732                 }
00733 
00734                 /* Receive a file. */
00735                 else {
00736                     while ((got = NutTcpReceive(sock, buf, mss)) > 0) {
00737                         int x;
00738                         if ((x = _write(fh, buf, got)) != got) {
00739                             ec = 552;
00740                             break;
00741                         }
00742                     }
00743                 }
00744                 free(buf);
00745             }
00746             NutTcpCloseSocket(sock);
00747         }
00748         _close(fh);
00749 
00750         /* Remove files received with an error. */
00751         if (mode == 0 && ec) {
00752             unlink(path);
00753         }
00754     }
00755     if (ec) {
00756         return NutFtpRespondBad(session, ec);
00757     }
00758     return NutFtpRespondOk(session, 226);
00759 }
00760 
00773 int NutFtpTransferDirectory(FTPSESSION * session, char *path)
00774 {
00775     TCPSOCKET *sock;
00776     FILE *fp;
00777 
00778     struct stat st;
00779     DIR *dir;
00780     struct dirent *d_ent;
00781     tm *gmt;
00782     u_long size;
00783     int ec = 550;
00784     char *name;
00785 
00786     dir = opendir(path);
00787     if (dir) {
00788         NutFtpSendMode(session, 0);
00789         if ((sock = NutFtpDataConnect(session)) != 0) {
00790             if ((fp = _fdopen((int) sock, "r+b")) != 0) {
00791                 ec = 0;
00792                 while ((d_ent = readdir(dir)) != 0) {
00793                     if (d_ent->d_name[0] == '.') {
00794                         continue;
00795                     }
00796 
00797                     if ((name = malloc(strlen(path) + strlen(d_ent->d_name) + 2)) != 0) {
00798                         sprintf(name, "%s/%s", path, d_ent->d_name);
00799                         if (stat(name, &st) == 0) {
00800                             if (st.st_mode) {
00801                                 fputc('d', fp);
00802                                 size = 0;
00803                             } else {
00804                                 fputc('-', fp);
00805                                 size = st.st_size;
00806                             }
00807                             fprintf(fp, "rw-rw-rw-  1 0 0 %6lu ", size);
00808                             gmt = gmtime(&st.st_mtime);
00809                             //fprintf(fp, "%s %u %u ", mon_name[gmt->tm_mon], gmt->tm_mday, 1900 + gmt->tm_year);
00810                             fprintf(fp, "%.3s %u ", mon_name + gmt->tm_mon * 3, gmt->tm_mday);
00811                             //fprintf(fp, "%02u:%02u:%02u ", gmt->tm_hour, gmt->tm_min, gmt->tm_sec);
00812                             fprintf(fp, "%02u:%02u ", gmt->tm_hour, gmt->tm_min);
00813                             fputs(d_ent->d_name, fp);
00814                             fputs("\r\n", fp);
00815                         }
00816                         free(name);
00817                     }
00818                 }
00819                 fclose(fp);
00820             }
00821             NutTcpCloseSocket(sock);
00822         }
00823         closedir(dir);
00824     }
00825     if (ec) {
00826         return NutFtpRespondBad(session, ec);
00827     }
00828     return NutFtpRespondOk(session, 226);
00829 }
00830 
00843 int NutFtpProcessMkd(FTPSESSION * session, char *path)
00844 {
00845     if (mkdir(path, 0777)) {
00846         return NutFtpRespondBad(session, 550);
00847     }
00848     return NutFtpRespondOk(session, 257);
00849 }
00850 
00863 int NutFtpProcessPass(FTPSESSION * session, char *pass)
00864 {
00865     if (ftp_pass && *ftp_pass) {
00866         if (session->ftp_login != 1 || strcmp(ftp_pass, pass)) {
00867             session->ftp_login = 0;
00868             return NutFtpRespondBad(session, 550);
00869         }
00870     }
00871     session->ftp_login = 2;
00872     return NutFtpRespondOk(session, 230);
00873 }
00874 
00888 int NutFtpProcessPassiv(FTPSESSION * session)
00889 {
00890     u_long ip = session->ftp_sock->so_local_addr;
00891     u_short port = 20;
00892 
00893     fprintf(session->ftp_stream, "227 Passive (%u,%u,%u,%u,%u,%u).\r\n",        /* */
00894             (u_char) ip, (u_char) (ip >> 8), (u_char) (ip >> 16), (u_char) (ip >> 24),  /* */
00895             (u_char) (port >> 8), (u_char) port);
00896     fflush(session->ftp_stream);
00897     session->ftp_passive = 1;
00898 
00899     return 0;
00900 }
00901 
00916 int NutFtpProcessPort(FTPSESSION * session, char *args)
00917 {
00918     if (ParseIpPort(args, &session->ftp_data_ip, &session->ftp_data_port) == 6) {
00919         if (session->ftp_sock->so_remote_addr == session->ftp_data_ip) {
00920             return NutFtpRespondOk(session, 200);
00921         }
00922         return NutFtpRespondBad(session, 425);
00923     }
00924     return NutFtpRespondBad(session, 501);;
00925 }
00926 
00939 int NutFtpProcessPwd(FTPSESSION * session)
00940 {
00941 #ifdef FTPD_DEBUG
00942     printf("\n<'257 \"%s\"' ", session->ftp_cwd);
00943 #endif
00944     fprintf(session->ftp_stream, "257 \"%s\"\r\n", session->ftp_cwd);
00945     return 0;
00946 }
00947 
00960 int NutFtpProcessRmd(FTPSESSION * session, char *path)
00961 {
00962     if (rmdir(path)) {
00963         return NutFtpRespondBad(session, 451);
00964     }
00965     return NutFtpRespondOk(session, 257);
00966 }
00967 
00977 int NutFtpProcessSystem(FTPSESSION * session)
00978 {
00979 #ifdef FTPD_DEBUG
00980     printf("\n<'215 UNIX Type: L8' ");
00981 #endif
00982     fputs("215 UNIX Type: L8\r\n", session->ftp_stream);
00983     return 0;
00984 }
00985 
01000 int NutFtpProcessType(FTPSESSION * session, char *typecode)
01001 {
01002     session->ftp_tran_mode = (*typecode != 'A') && (*typecode != 'a');
01003     return NutFtpRespondOk(session, 200);
01004 }
01005 
01018 int NutFtpProcessUser(FTPSESSION * session, char *user)
01019 {
01020     if (ftp_user && *ftp_user) {
01021         if (session->ftp_login && strcmp(ftp_user, user)) {
01022             session->ftp_login = 0;
01023             return NutFtpRespondBad(session, 550);
01024         }
01025     }
01026 
01027     /* Need a password too. */
01028     if (ftp_pass && *ftp_pass) {
01029         session->ftp_login = 1;
01030         return NutFtpRespondOk(session, 331);
01031     }
01032 
01033     /* No password required. */
01034     session->ftp_login = 2;
01035     return NutFtpRespondOk(session, 230);
01036 }
01037 
01049 int NutFtpProcessRequest(FTPSESSION * session, char *request)
01050 {
01051     int rc = 0;
01052     char *cmd;
01053     char *args;
01054 
01055     /* Split the line into command and argument part. */
01056     SplitCmdArg(request, &cmd, &args);
01057 #ifdef FTPD_DEBUG
01058     printf("\n>'%s %s' ", cmd, args);
01059 #endif
01060 
01061     /* QUIT - Terminate session. */
01062     if (strcmp_P(cmd, cmd_quit_P) == 0) {
01063         NutFtpRespondOk(session, 221);
01064         rc = -1;
01065     }
01066 
01067     /* USER <username> - Check user name. */
01068     else if (strcmp_P(cmd, cmd_user_P) == 0) {
01069         rc = NutFtpProcessUser(session, args);
01070     }
01071 
01072     /* PASS <password> - Check user password. */
01073     else if (strcmp_P(cmd, cmd_pass_P) == 0) {
01074         rc = NutFtpProcessPass(session, args);
01075     } else if (strcmp_P(cmd, cmd_noop_P) == 0) {
01076         NutFtpRespondOk(session, 200);
01077     }
01078     /* Anything else requires a successful login. */
01079     else if (session->ftp_login < 2) {
01080         rc = NutFtpRespondBad(session, 530);
01081     }
01082 
01083     /* Valid login. */
01084     else {
01085 
01086         /* PASV - Prepare passive transfer. */
01087         if (strcmp_P(cmd, cmd_pasv_P) == 0) {
01088             rc = NutFtpProcessPassiv(session);
01089         }
01090 
01091         /* PORT <host-port> - Set data connection. */
01092         else if (strcmp_P(cmd, cmd_port_P) == 0) {
01093             rc = NutFtpProcessPort(session, args);
01094         }
01095 
01096         /* [X]PWD - Send name of current working directory. */
01097         else if (strcmp_P(cmd, cmd_pwd_P) == 0 || strcmp_P(cmd, cmd_xpwd_P) == 0) {
01098             rc = NutFtpProcessPwd(session);
01099         }
01100 
01101         /* SYST - Send system identifier. */
01102         else if (strcmp_P(cmd, cmd_syst_P) == 0) {
01103             rc = NutFtpProcessSystem(session);
01104         }
01105 
01106         /* TYPE <type-code> - Receive transfer mode. */
01107         else if (strcmp_P(cmd, cmd_type_P) == 0) {
01108             rc = NutFtpProcessType(session, args);
01109         }
01110 
01111         /* Commands with path name argument. */
01112         else {
01113             char *path;
01114 
01115             if ((path = CreateFullPathName(ftp_root, session->ftp_cwd, args)) == 0) {
01116                 rc = NutFtpRespondBad(session, 451);
01117             }
01118 
01119             /* CWD <pathname> - Change working directory. */
01120             else if (strcmp_P(cmd, cmd_cwd_P) == 0) {
01121                 rc = NutFtpProcessCwd(session, path);
01122             }
01123 
01124             /* DELE <pathname> - Delete a file. */
01125             else if (strcmp_P(cmd, cmd_dele_P) == 0) {
01126                 rc = NutFtpProcessDelete(session, path);
01127             }
01128 
01129             /* LIST | NLST [<pathname>] - Send list of files in a directory. */
01130             else if (strcmp_P(cmd, cmd_list_P) == 0 || strcmp_P(cmd, cmd_nlst_P) == 0) {
01131                 rc = NutFtpTransferDirectory(session, path);
01132             }
01133 
01134             /* MKD <pathname> - Make a directory. */
01135             else if (strcmp_P(cmd, cmd_mkd_P) == 0 || strcmp_P(cmd, cmd_xmkd_P) == 0) {
01136                 rc = NutFtpProcessMkd(session, path);
01137             }
01138 
01139             /* RETR <pathname> - Send a file to the client. */
01140             else if (strcmp_P(cmd, cmd_retr_P) == 0) {
01141                 rc = NutFtpTransferFile(session, path, 1);
01142             }
01143 
01144             /* RMD <pathname> - Remove a directory. */
01145             else if (strcmp_P(cmd, cmd_rmd_P) == 0 || strcmp_P(cmd, cmd_xrmd_P) == 0) {
01146                 rc = NutFtpProcessRmd(session, path);
01147             }
01148 
01149             /* STOR <pathname> - Receive a file from the client. */
01150             else if (strcmp_P(cmd, cmd_stor_P) == 0) {
01151                 rc = NutFtpTransferFile(session, path, 0);
01152             }
01153 
01154             /* Anything else is an unknown command. */
01155             else {
01156                 rc = NutFtpRespondBad(session, 502);
01157             }
01158 
01159             if (path) {
01160                 free(path);
01161             }
01162         }
01163     }
01164     return rc;
01165 }
01166 
01182 int NutFtpServerSession(TCPSOCKET * sock)
01183 {
01184     int rc = 0;
01185     FTPSESSION *session;
01186     char *buff;
01187     time_t now;
01188     struct _tm *tip;
01189     char ch;
01190 
01191     /* Set the root path if not yet done. */
01192     if (NutRegisterFtpRoot(ftp_root)) {
01193         return -1;
01194     }
01195 
01196     /* Allocate the command line buffer. */
01197     if ((buff = malloc(FTP_MAX_CMDBUF)) == 0) {
01198         return -1;
01199     }
01200 
01201     /* Create a session structure and open a stream. */
01202     if ((session = NutFtpOpenSession(sock)) == 0) {
01203         free(buff);
01204         return -1;
01205     }
01206 
01207     /* Send a welcome banner including system time. */
01208     time(&now);
01209     tip = localtime(&now);
01210 #ifdef FTPD_DEBUG
01211     printf("\n<'");
01212     printf_P(rep_banner, NutVersionString(), &mon_name[tip->tm_mon * 3],        /* */
01213              tip->tm_mday, tip->tm_hour, tip->tm_min, tip->tm_sec);
01214 #endif
01215     fprintf_P(session->ftp_stream, rep_banner, NutVersionString(),      /* */
01216               &mon_name[tip->tm_mon * 3],       /* */
01217               tip->tm_mday, tip->tm_hour, tip->tm_min, tip->tm_sec);
01218 
01219     /* 
01220      * Loop for requests. 
01221      */
01222     while (rc == 0) {
01223 
01224         /* Flush any previous output and read a new command line. */
01225         fflush(session->ftp_stream);
01226         if (fgets(buff, FTP_MAX_CMDBUF, session->ftp_stream) == 0) {
01227             rc = -1;
01228             break;
01229         }
01230 
01231         /* Skip command lines, which are too long. */
01232         if ((ch = *(buff + strlen(buff) - 1)) != '\n' && ch != '\r') {
01233             do {
01234                 if (fgets(buff, FTP_MAX_CMDBUF, session->ftp_stream) == 0) {
01235                     rc = -1;
01236                     break;
01237                 }
01238             } while ((ch = *(buff + strlen(buff) - 1)) != '\n' && ch != '\r');
01239             if (rc == 0) {
01240                 rc = NutFtpRespondBad(session, 500);
01241             }
01242         }
01243 
01244         /* Process the request. */
01245         else {
01246             rc = NutFtpProcessRequest(session, buff);
01247         }
01248     }
01249 
01250     /* Cleanup and return. */
01251     NutFtpCloseSession(session);
01252     free(buff);
01253     return rc;
01254 }
01255 

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