cuftp

#ifndef _CUFTPD_H
#define _CUFTPD_H

#define CUFTPD_DEBUG(fmt, ...)        cuftpd_debug(__FILE__, __LINE__, fmt, __VA_ARGS__)
#define CUFTPD_ARR_LEN(arr)                (sizeof(arr)/sizeof(arr[0]))

#define CUFTPD_VER                                "1.0"
#define CUFTPD_DEF_SRV_PORT                21
#define CUFTPD_LISTEN_QU_LEN        8
#define CUFTPD_LINE_END                        "/r/n"

#define CUFTPD_OK        0
#define CUFTPD_ERR        (-1)
#define PATH_MAX 128

#define CUFTPD_CHECK_LOGIN()  /
        do { /
                if (!cuftpd_cur_user) { /
                        cuftpd_send_resp(ctrlfd, 530, "first please"); /
                        return CUFTPD_ERR; /
                } /
        } while(0)

struct cuftpd_cmd_struct {
        char *cmd_name;
        int (*cmd_handler)(int ctrlfd, char *cmd_line);
};

struct cuftpd_user_struct {
        char user[128];
        char pass[128];
};


#endif
/*
* A very simple ftp server's source code for demonstration.
* It supports PASV/PORT modes and following operations:
*   ls,pwd,cwd,get,put,dele.
* I have tested it using following ftp clients:
* 1. Windows XP's command line ftp client,
* 2. IE 6.0,
* 3. Redhat 9.0's ftp client,
* 4. CuteFTP 8,
* I'll introduce more functions and improve its performance
* if i have enough idle time afterwards.
* Any issues pls paste to CU.
*
* Change History:
* 11/24/2006                1.0                        Initial version.
*/
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/stat.h>
#include <time.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <stdarg.h>
#include <signal.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <pwd.h>
#include <grp.h>
#include <dirent.h>

#include "cuftpd.h"

/* local functions declarations */
static int cuftpd_do_user(int,char*);
static int cuftpd_do_pass(int,char*);
static int cuftpd_do_pwd(int, char*);
static int cuftpd_do_cwd(int, char*);
static int cuftpd_do_syst(int,char*);
static int cuftpd_do_list(int,char*);
static int cuftpd_do_size(int,char*);
static int cuftpd_do_dele(int,char*);
static int cuftpd_do_type(int,char*);
static int cuftpd_do_port(int,char*);
static int cuftpd_do_pasv(int,char*);
static int cuftpd_do_retr(int,char*);
static int cuftpd_do_stor(int,char*);
static int cuftpd_do_quit(int,char*);

/* global variables */
int cuftpd_debug_on;
int cuftpd_srv_port = CUFTPD_DEF_SRV_PORT;
int cuftpd_cur_child_num;
int cuftpd_quit_flag;
struct cuftpd_user_struct *cuftpd_cur_user;
int cuftpd_pasv_fd = -1;
int cuftpd_pasv_connfd = -1;
int cuftpd_port_connfd = -1;
char cuftpd_home_dir[PATH_MAX];

/*
* Currently supported ftp commands.
*/
struct cuftpd_cmd_struct cuftpd_cmds[] = {
        {"USER", cuftpd_do_user},
        {"PASS", cuftpd_do_pass},
        {"PWD",  cuftpd_do_pwd},
        {"XPWD", cuftpd_do_pwd},
        {"CWD",  cuftpd_do_cwd},
        {"LIST", cuftpd_do_list},
        {"NLST", cuftpd_do_list},
        {"SYST", cuftpd_do_syst},
        {"TYPE", cuftpd_do_type},
        {"SIZE", cuftpd_do_size},
        {"DELE", cuftpd_do_dele},
        {"RMD",  cuftpd_do_dele},
        {"PORT", cuftpd_do_port},
        {"PASV", cuftpd_do_pasv},
        {"RETR", cuftpd_do_retr},
        {"STOR", cuftpd_do_stor},
        {"QUIT", cuftpd_do_quit},
        { NULL,         NULL}
};

/*
* Anonymous users, you can add more user/pass pairs here.
*/
struct cuftpd_user_struct cuftpd_users[] = {
        {"anonymous", ""},
        {"ftp", ""}
};

/*
* Ftp server's responses, and are not complete.
*/
char cuftpd_srv_resps[][256] = {
        "150 Begin transfer"                                                        CUFTPD_LINE_END,
        "200 OK"                                                                                CUFTPD_LINE_END,
        "213 %d"                                                                                CUFTPD_LINE_END,
        "215 UNIX Type: L8"                                                                CUFTPD_LINE_END,
        "220 CuFTPD " CUFTPD_VER " Server"                                CUFTPD_LINE_END,
        "221 Goodbye"                                                                        CUFTPD_LINE_END,
        "226 Transfer complete"                                                        CUFTPD_LINE_END,
        "227 Entering Passive Mode (%d,%d,%d,%d,%d,%d)"        CUFTPD_LINE_END,
        "230 User %s logged in"                                                        CUFTPD_LINE_END,
        "250 CWD command successful"                                        CUFTPD_LINE_END,
        "257 /"%s/" is current directory"                                CUFTPD_LINE_END,
        "331 Password required for %s"                                        CUFTPD_LINE_END,
        "500 Unsupport command %s"                                                CUFTPD_LINE_END,
        "530 Login %s"                                                                        CUFTPD_LINE_END,
        "550 Error"                                                                                CUFTPD_LINE_END
};

 

static void
cuftpd_debug(const char *file, int line, const char *fmt, ...)
{
        va_list ap;

        if (!cuftpd_debug_on)
                return;

        fprintf(stderr, "(%s:%d:%d)", file, line, getpid());
        va_start(ap, fmt);
        vfprintf(stderr, fmt, ap);
        va_end(ap);
}

static void
cuftpd_usage(void)
{
        printf("cuftpd " CUFTPD_VER " usage:/n");
        printf("cuftpd -p port -d/n");
}

static void
cuftpd_parse_args(int argc, char *argv[])
{
        int opt;
        int err = 0;

        while ((opt = getopt(argc, argv, "p:dh")) != -1) {
                switch (opt) {
                        case 'p':
                            cuftpd_srv_port = atoi(optarg);
                                err = (cuftpd_srv_port < 0 || cuftpd_srv_port > 65535);          
                            break;
                        case 'd':
                            cuftpd_debug_on = 1;
                            break;
                        default:
                            err = 1;
                            break;
                }
               
                if (err) {
                        cuftpd_usage();
                        exit(-1);
                }
        }

        CUFTPD_DEBUG("srv port:%d/n", cuftpd_srv_port);
}

static void cuftpd_sigchild(int signo)
{
        int status;

        if (signo != SIGCHLD)
                return;

        while (waitpid(-1, &status, WNOHANG) > 0)
                cuftpd_cur_child_num--;

        CUFTPD_DEBUG("caught a SIGCHLD, cuftpd_cur_child_num=%d/n", cuftpd_cur_child_num);
}

static int cuftpd_init(void)
{
        /* add all init statements here */

        signal(SIGPIPE, SIG_IGN);
        signal(SIGCHLD, cuftpd_sigchild);
        getcwd(cuftpd_home_dir, sizeof(cuftpd_home_dir));

        return CUFTPD_OK;
}

/*
* Create ftp server's listening socket.
*/
static int
cuftpd_create_srv(void)
{
        int fd;
        int on = 1;
        int err;
        struct sockaddr_in srvaddr;

        if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
                CUFTPD_DEBUG("socket() failed: %s/n", strerror(errno));
                return fd;
        }

        err = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
        if (err < 0) {
                CUFTPD_DEBUG("setsockopt() failed: %s/n", strerror(errno));
                close(fd);
                return CUFTPD_ERR;
        }
       
        memset(&srvaddr, 0, sizeof(srvaddr));
        srvaddr.sin_family = AF_INET;
        srvaddr.sin_port = htons(cuftpd_srv_port);
        srvaddr.sin_addr.s_addr = htonl(INADDR_ANY);
        err = bind(fd, (struct sockaddr*)&srvaddr, sizeof(srvaddr));
        if (err < 0) {
                CUFTPD_DEBUG("bind() failed: %s/n", strerror(errno));
                close(fd);
                return CUFTPD_ERR;
        }

        err = listen(fd, CUFTPD_LISTEN_QU_LEN);
        if (err < 0) {
                CUFTPD_DEBUG("listen() failed: %s/n", strerror(errno));
                close(fd);
                return CUFTPD_ERR;
        }

        if (cuftpd_debug_on) {
                int len = sizeof(srvaddr);
                getsockname(fd, (struct sockaddr*)&srvaddr, &len);
                CUFTPD_DEBUG("create srv listen socket OK: %s:%d/n",
                           inet_ntoa(srvaddr.sin_addr), ntohs(srvaddr.sin_port));
        }

        return fd;       

}

/*
* Map server response's number to the msg pointer.
*/
static char *
cuftpd_srv_resp_num2msg(int num)
{
        int i;
        char buf[8];

        snprintf(buf, sizeof(buf), "%d", num);
        if (strlen(buf) != 3)
                return NULL;

        for (i = 0; i < CUFTPD_ARR_LEN(cuftpd_srv_resps); i++)
                if (strncmp(buf, cuftpd_srv_resps[i], strlen(buf)) == 0)
                        return cuftpd_srv_resps[i];

        return NULL;
}

static int
cuftpd_send_msg(int fd, char *msg, int len)
{
        int n, off = 0, left = len;

        while (1) {
                n = write(fd, msg + off, left);
                if (n < 0) {
                        if (errno == EINTR)
                                continue;
                        return n;
                }
                if (n < left) {
                        left -= n;
                        off += n;
                        continue;
                }
                return len;
        }
}

static int
cuftpd_recv_msg(int fd, char buf[], int len)
{
        int n;

        while (1) {
                n = read(fd, buf, len);
                if (n < 0) {
                        if (errno == EINTR)
                                continue;
                        return n;
                }
                return n;
        }
}

static int
cuftpd_send_resp(int fd, int num, ...)
{
        char *cp = cuftpd_srv_resp_num2msg(num);
        va_list ap;
        char buf[BUFSIZ];

        if (!cp) {
                CUFTPD_DEBUG("cuftpd_srv_resp_num2msg(%d) failed/n", num);
                return CUFTPD_ERR;
        }

        va_start(ap, num);
        vsnprintf(buf, sizeof(buf), cp, ap);
        va_end(ap);

        CUFTPD_DEBUG("send resp:%s/n", buf);
        if (cuftpd_send_msg(fd, buf, strlen(buf)) != strlen(buf)) {
                CUFTPD_DEBUG("cuftpd_send_msg() failed: %s/n", strerror(errno));
                return CUFTPD_ERR;
        }

        return CUFTPD_OK;
}

static void
cuftpd_trim_lineend(char *cp)
{
        if (cp && strlen(cp) > 0) {
                char *cp2 = &cp[strlen(cp) - 1];
               
                while (*cp2 == '/r' || *cp2 == '/n')
                        if (--cp2 < cp)
                                break;
                cp2[1] = '/0';
        }
}

static int
cuftpd_get_connfd(void)
{
        int fd;

        if (cuftpd_pasv_fd >= 0) {
                fd = accept(cuftpd_pasv_fd, NULL, NULL);
                if (fd >= 0) {
                        close(cuftpd_pasv_fd);
                        cuftpd_pasv_fd = -1;
                        cuftpd_pasv_connfd = fd;
                        return fd;
                }
                else
                        CUFTPD_DEBUG("accept() failed:%s/n", strerror(errno));
        }
        else if (cuftpd_port_connfd >= 0)
                return cuftpd_port_connfd;
               
        return (-1);
}

static int
cuftpd_close_all_fd(void)
{
        if (cuftpd_pasv_fd >= 0) {
                close(cuftpd_pasv_fd);
                cuftpd_pasv_fd = -1;
        }
        if (cuftpd_pasv_connfd >= 0) {
                close(cuftpd_pasv_connfd);
                cuftpd_pasv_connfd = -1;
        }
        if (cuftpd_port_connfd >= 0) {
                close(cuftpd_port_connfd);
                cuftpd_port_connfd = -1;
        }
        return CUFTPD_OK;
}
static int
cuftpd_do_user(int ctrlfd, char *cmdline)
{
        char *cp = strchr(cmdline, ' ');

        if (cp) {
                int i;

                for (i = 0; i < CUFTPD_ARR_LEN(cuftpd_users); i++)
                        if (strcmp(cp + 1, cuftpd_users[i].user) == 0) {
                                CUFTPD_DEBUG("user(%s) is found/n", cp + 1);
                                cuftpd_cur_user = &cuftpd_users[i];
                                break;
                        }

                if (!cuftpd_cur_user)
                        CUFTPD_DEBUG("user(%s) not found/n", cp + 1);
               
                /*
                 * If user name is bad, we still don't close the connection
                 * and send back the 331 response to ask for password.
                 */
                return cuftpd_send_resp(ctrlfd, 331, cp + 1);
        }
       
        return cuftpd_send_resp(ctrlfd, 550);
}

static int
cuftpd_do_pass(int ctrlfd, char *cmdline)
{
        char *space = strchr(cmdline, ' ');

        if (cuftpd_cur_user && space) {
                if (strlen(cuftpd_cur_user->pass) == 0 ||
                        strcmp(space + 1, cuftpd_cur_user->pass) == 0) {
                        CUFTPD_DEBUG("password for %s OK/n", cuftpd_cur_user->user);
                        return cuftpd_send_resp(ctrlfd, 230, cuftpd_cur_user->user);
                }
                CUFTPD_DEBUG("password for %s ERR/n", cuftpd_cur_user->user);
        }
               
        /*
         * User and pass don't match or
         * cmd line does not contain a space character.
         */
        cuftpd_cur_user = NULL;
        return cuftpd_send_resp(ctrlfd, 530, "incorrect");
}

static int
cuftpd_do_pwd(int ctrlfd, char *cmdline)
{
        char curdir[PATH_MAX];
        char *cp;
       
        CUFTPD_CHECK_LOGIN();

        getcwd(curdir, sizeof(curdir));
        cp = &curdir[strlen(cuftpd_home_dir)];
        return cuftpd_send_resp(ctrlfd, 257, (*cp == '/0') ? "/" : cp);
}

static int
cuftpd_do_cwd(int ctrlfd, char *cmdline)
{
        char *space = strchr(cmdline, ' ');
        char curdir[PATH_MAX];

        CUFTPD_CHECK_LOGIN();

        if (!space)
                return cuftpd_send_resp(ctrlfd, 550);

        getcwd(curdir, sizeof(curdir));
        if (strcmp(curdir, cuftpd_home_dir) == 0 &&
                space[1] == '.' &&
                space[2] == '.')
                return cuftpd_send_resp(ctrlfd, 550);

        /* Absolute path */       
        if (space[1] == '/') {
                if (chdir(cuftpd_home_dir) == 0) {
                        if (space[2] == '/0' || chdir(space+2) == 0)
                                return cuftpd_send_resp(ctrlfd, 250);       
                }
                chdir(curdir);
                return cuftpd_send_resp(ctrlfd, 550);
        }

        /* Relative path */
        if (chdir(space+1) == 0)
                return cuftpd_send_resp(ctrlfd, 250);

        chdir(curdir);
        return cuftpd_send_resp(ctrlfd, 550);
}

/*
* This function acts as a implementation like 'ls -l' shell command.
*/
static int
cuftpd_get_list(char buf[], int len)
{
        DIR *dir;
        struct dirent *ent;
        int off = 0;

        if ((dir = opendir(".")) < 0) {
                CUFTPD_DEBUG("opendir() failed:%s/n", strerror(errno));
                return CUFTPD_ERR;
        }

        buf[0] = '/0';

        while ((ent = readdir(dir)) != NULL) {
                char *filename = ent->d_name;
                struct stat st;
                char mode[] = "----------";
                struct passwd *pwd;
                struct group *grp;
                struct tm *ptm;
                char timebuf[BUFSIZ];
                int timelen;

                if (strcmp(filename, ".") == 0 ||
                        strcmp(filename, "..") == 0)
                        continue;

                if (stat(filename, &st) < 0) {
                        closedir(dir);
                        CUFTPD_DEBUG("stat() failed:%s/n", strerror(errno));
                        return CUFTPD_ERR;
                }

                if (S_ISDIR(st.st_mode))
                        mode[0] = 'd';
                if (st.st_mode & S_IRUSR)
                        mode[1] = 'r';
                if (st.st_mode & S_IWUSR)
                        mode[2] = 'w';
                if (st.st_mode & S_IXUSR)
                        mode[3] = 'x';
                if (st.st_mode & S_IRGRP)
                        mode[4] = 'r';
                if (st.st_mode & S_IWGRP)
                        mode[5] = 'w';
                if (st.st_mode & S_IXGRP)
                        mode[6] = 'x';
                if (st.st_mode & S_IROTH)
                        mode[7] = 'r';
                if (st.st_mode & S_IWOTH)
                        mode[8] = 'w';
                if (st.st_mode & S_IXOTH)
                        mode[9] = 'x';
                mode[10] = '/0';
                off += snprintf(buf + off, len - off, "%s ", mode);

                /* hard link number, this field is nonsense for ftp */
                off += snprintf(buf + off, len - off, "%d ", 1);

                /* user */
                if ((pwd = getpwuid(st.st_uid)) == NULL) {
                        closedir(dir);
                        return CUFTPD_ERR;
                }
                off += snprintf(buf + off, len - off, "%s ", pwd->pw_name);

                /* group */
                if ((grp = getgrgid(st.st_gid)) == NULL) {
                        closedir(dir);
                        return CUFTPD_ERR;
                }
                off += snprintf(buf + off, len - off, "%s ", grp->gr_name);

                /* size */
                off += snprintf(buf + off, len - off, "%*d ", 10, st.st_size);

                /* mtime */
                ptm = localtime(&st.st_mtime);
                if (ptm && (timelen = strftime(timebuf, sizeof(timebuf), "%b %d %H:%S", ptm)) > 0) {
                        timebuf[timelen] = '/0';
                        off += snprintf(buf + off, len - off, "%s ", timebuf);
                }
                else {
                        closedir(dir);
                        return CUFTPD_ERR;
                }
               
                off += snprintf(buf + off, len - off, "%s/r/n", filename);
               
        }

        return off;
}

static int
cuftpd_do_list(int ctrlfd, char *cmdline)
{
        char buf[BUFSIZ];
        int n;
        int fd;

        CUFTPD_CHECK_LOGIN();

        if ((fd = cuftpd_get_connfd()) < 0) {
                CUFTPD_DEBUG("LIST cmd:no available fd%s", "/n");
                goto err_label;
        }

        cuftpd_send_resp(ctrlfd, 150);

        /*
         * Get the 'ls -l'-like result and send it to client.
         */
        n = cuftpd_get_list(buf, sizeof(buf));
        if (n >= 0) {
                if (cuftpd_send_msg(fd, buf, n) != n) {
                        CUFTPD_DEBUG("cuftpd_send_msg() failed: %s/n", strerror(errno));
                        goto err_label;
                }
        }
        else {
                CUFTPD_DEBUG("cuftpd_get_list() failed %s", "/n");
                goto err_label;
        }
       
        cuftpd_close_all_fd();
        return cuftpd_send_resp(ctrlfd, 226);

err_label:
        cuftpd_close_all_fd();
        return cuftpd_send_resp(ctrlfd, 550);
}

static int
cuftpd_do_syst(int ctrlfd, char *cmdline)
{
        CUFTPD_CHECK_LOGIN();
        return cuftpd_send_resp(ctrlfd, 215);
}

static int
cuftpd_do_size(int ctrlfd, char *cmdline)
{
        char *space = strchr(cmdline, ' ');
        struct stat st;

        CUFTPD_CHECK_LOGIN();

        if (!space || lstat(space + 1, &st) < 0) {
                CUFTPD_DEBUG("SIZE cmd err: %s/n", cmdline);
                return cuftpd_send_resp(ctrlfd, 550);
        }

        return cuftpd_send_resp(ctrlfd, 213, st.st_size);
}

static int
cuftpd_do_dele(int ctrlfd, char *cmdline)
{
        char *space = strchr(cmdline, ' ');
        struct stat st;

        CUFTPD_CHECK_LOGIN();

        if (!space || lstat(space+1, &st) < 0 ||
                remove(space+1) < 0) {
                CUFTPD_DEBUG("DELE cmd err: %s/n", cmdline);
                return cuftpd_send_resp(ctrlfd, 550);
        }

        return cuftpd_send_resp(ctrlfd, 200);
}

static int
cuftpd_do_type(int ctrlfd, char *cmdline)
{
        CUFTPD_CHECK_LOGIN();

        /*
         * Just send back 200 response and do nothing
         */
        return cuftpd_send_resp(ctrlfd, 200);
}

/*
* Parse PORT cmd and fetch the ip and port,
* and both in network byte order.
*/
static int
cuftpd_get_port_mode_ipport(char *cmdline, unsigned int *ip, unsigned short *port)
{
        char *cp = strchr(cmdline, ' ');
        int i;
        unsigned char buf[6];

        if (!cp)
                return CUFTPD_ERR;

        for (cp++, i = 0; i < CUFTPD_ARR_LEN(buf); i++) {
                buf[i] = atoi(cp);
                cp = strchr(cp, ',');
                if (!cp && i < CUFTPD_ARR_LEN(buf) - 1)
                        return CUFTPD_ERR;
                cp++;
        }

        if (ip)
                *ip = *(unsigned int*)&buf[0];

        if (port)
                *port = *(unsigned short*)&buf[4];

        return CUFTPD_OK;
}

/*
* Ftp client shipped with Windows XP uses PORT
* mode as default to connect ftp server.
*/
static int
cuftpd_do_port(int ctrlfd, char *cmdline)
{
        unsigned int ip;
        unsigned short port;
        struct sockaddr_in sin;

        CUFTPD_CHECK_LOGIN();

        if (cuftpd_get_port_mode_ipport(cmdline, &ip, &port) != CUFTPD_OK) {
                CUFTPD_DEBUG("cuftpd_get_port_mode_ipport() failed%s", "/n");
                goto err_label;
        }

        memset(&sin, 0, sizeof(sin));
        sin.sin_family = AF_INET;
        sin.sin_addr.s_addr = ip;
        sin.sin_port = port;
       
        CUFTPD_DEBUG("PORT cmd:%s:%d/n", inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));

        if (cuftpd_port_connfd >= 0) {
                close(cuftpd_port_connfd);
                cuftpd_port_connfd = -1;
        }

        cuftpd_port_connfd = socket(AF_INET, SOCK_STREAM, 0);
        if (cuftpd_port_connfd < 0) {
                CUFTPD_DEBUG("socket() failed:%s/n", strerror(errno));
                goto err_label;
        }

        if (connect(cuftpd_port_connfd, (struct sockaddr*)&sin, sizeof(sin)) < 0) {
                CUFTPD_DEBUG("bind() failed:%s/n", strerror(errno));
                goto err_label;
        }

        CUFTPD_DEBUG("PORT mode connect OK%s", "/n");
        return cuftpd_send_resp(ctrlfd, 200);

err_label:
        if (cuftpd_port_connfd >= 0) {
                close(cuftpd_port_connfd);
                cuftpd_port_connfd = -1;
        }
        return cuftpd_send_resp(ctrlfd, 550);

}

static int
cuftpd_do_pasv(int ctrlfd, char *cmdline)
{
        struct sockaddr_in pasvaddr;
        int len;
        unsigned int ip;
        unsigned short port;

        CUFTPD_CHECK_LOGIN();

        if (cuftpd_pasv_fd >= 0) {
                close(cuftpd_pasv_fd);
                cuftpd_pasv_fd = -1;
        }

        cuftpd_pasv_fd = socket(AF_INET, SOCK_STREAM, 0);
        if (cuftpd_pasv_fd < 0) {
                CUFTPD_DEBUG("socket() failed: %s/n", strerror(errno));
                return cuftpd_send_resp(ctrlfd, 550);
        }

        /*
         * must bind to the same interface as ctrl connectin came from.
         */
        len = sizeof(pasvaddr);
        getsockname(ctrlfd, (struct sockaddr*)&pasvaddr, &len);
        pasvaddr.sin_port = 0;

        if (bind(cuftpd_pasv_fd, (struct sockaddr*)&pasvaddr, sizeof(pasvaddr)) < 0) {
                CUFTPD_DEBUG("bind() failed: %s/n", strerror(errno));
                close(cuftpd_pasv_fd);
                cuftpd_pasv_fd = -1;
                return cuftpd_send_resp(ctrlfd, 550);
        }

        if (listen(cuftpd_pasv_fd, CUFTPD_LISTEN_QU_LEN) < 0) {
                CUFTPD_DEBUG("listen() failed: %s/n", strerror(errno));
                close(cuftpd_pasv_fd);
                cuftpd_pasv_fd = -1;
                return cuftpd_send_resp(ctrlfd, 550);
        }
               
        len = sizeof(pasvaddr);
        getsockname(cuftpd_pasv_fd, (struct sockaddr*)&pasvaddr, &len);
        ip = ntohl(pasvaddr.sin_addr.s_addr);
        port = ntohs(pasvaddr.sin_port);
        CUFTPD_DEBUG("local bind: %s:%d/n", inet_ntoa(pasvaddr.sin_addr), port);

        /*
         * write local ip/port into response msg
         * and send to client.
         */
        return cuftpd_send_resp(ctrlfd, 227, (ip>>24)&0xff, (ip>>16)&0xff,
                        (ip>>8)&0xff, ip&0xff, (port>>8)&0xff, port&0xff);

}

static int
cuftpd_do_retr(int ctrlfd, char *cmdline)
{
        char buf[BUFSIZ];
        char *space = strchr(cmdline, ' ');
        struct stat st;
        int fd = -1, n;
        int connfd;

        CUFTPD_CHECK_LOGIN();

        if (!space || lstat(space + 1, &st) < 0) {
                CUFTPD_DEBUG("RETR cmd err: %s/n", cmdline);
                goto err_label;
        }

 &nb

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值