⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ftpd.c

📁 功能强大的ftp服务器源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
void dopasv(int psvtype){    struct sockaddr_storage dataconn;    /* my data connection endpoint */        unsigned long a = 0U;    unsigned int p;    int on;    unsigned int firstporttried;    if (loggedin == 0) {        addreply_noformat(530, MSG_NOT_LOGGED_IN);        return;    }    if (datafd != -1) {                /* for buggy clients */        (void) close(datafd);        datafd = -1;    }    fourinsix(&ctrlconn);    if (STORAGE_FAMILY(ctrlconn) == AF_INET6 && psvtype == 0) {        addreply_noformat(425, MSG_CANT_PASV);        return;    }    firstporttried = firstport + zrand() % (lastport - firstport + 1);    p = firstporttried;    datafd = socket(STORAGE_FAMILY(ctrlconn), SOCK_STREAM, IPPROTO_TCP);    if (datafd == -1) {        error(425, MSG_CANT_PASSIVE);        return;    }    on = 1;    if (setsockopt(datafd, SOL_SOCKET, SO_REUSEADDR,                   (char *) &on, sizeof on) < 0) {        error(421, "setsockopt");        return;    }        dataconn = ctrlconn;    for (;;) {        if (STORAGE_FAMILY(dataconn) == AF_INET6) {            STORAGE_PORT6(dataconn) = htons(p);        } else {            STORAGE_PORT(dataconn) = htons(p);        }        if (bind(datafd, (struct sockaddr *) &dataconn,                 STORAGE_LEN(dataconn)) == 0) {            break;        }        p--;        if (p < firstport) {            p = lastport;        }        if (p == firstporttried) {            (void) close(datafd);            datafd = -1;            addreply_noformat(425, MSG_PORTS_BUSY);            return;        }    }    alarm(idletime);    if (listen(datafd, DEFAULT_BACKLOG_DATA) < 0) {        (void) close(datafd);        datafd = -1;        error(425, MSG_GETSOCKNAME_DATA);        return;    }    switch (psvtype) {    case 0:        if (STORAGE_FAMILY(force_passive_ip) == 0) {            a = ntohl(STORAGE_SIN_ADDR(dataconn));        } else if (STORAGE_FAMILY(force_passive_ip) == AF_INET6) {            (void) close(datafd);            datafd = -1;            addreply_noformat(425, MSG_NO_EPSV);            return;        } else if (STORAGE_FAMILY(force_passive_ip) == AF_INET) {            a = ntohl(STORAGE_SIN_ADDR(force_passive_ip));        } else {            _EXIT(EXIT_FAILURE);        }/* According to RFC, any message can follow 227. But broken NAT gateways * and connection tracking code rely on this. So don't translate the following * messages */        addreply(227, "Entering Passive Mode (%lu,%lu,%lu,%lu,%u,%u)",                 (a >> 24) & 255, (a >> 16) & 255, (a >> 8) & 255, a & 255,                 (p >> 8) & 255, p & 255);        break;    case 1:        addreply(229, "Extended Passive mode OK (|||%u|)", p);        break;    case 2:        addreply(227, "%u", p);        break;    default:        _EXIT(EXIT_FAILURE);    }    passive = 1;}void doport(const char *arg){    unsigned int a1, a2, a3, a4, p1, p2;    struct sockaddr_storage a;    if (6 != sscanf(arg, "%u,%u,%u,%u,%u,%u",                    &a1, &a2, &a3, &a4, &p1, &p2) ||        a1 > 255 || a2 > 255 || a3 > 255 || a4 > 255 ||        p1 > 255 || p2 > 255 || (a1|a2|a3|a4) == 0 ||        (p1|p2) == 0) {        addreply_noformat(501, MSG_SYNTAX_ERROR_IP);        return;    }    memset(&a, 0, sizeof a);    STORAGE_FAMILY(a) = AF_INET;    STORAGE_SIN_ADDR(a) =        htonl((a1 << 24) | (a2 << 16) | (a3 << 8) | a4);    SET_STORAGE_LEN(a, sizeof(struct sockaddr_in));    doport2(a, (p1 << 8) | p2);}#ifndef WITH_PRIVSEPstatic int doport3(const int protocol){    struct sockaddr_storage dataconn;  /* his endpoint */        # ifndef NON_ROOT_FTP    static const unsigned short portlist[] = FTP_ACTIVE_SOURCE_PORTS;    const unsigned short *portlistpnt = portlist;# else    static const unsigned short portlist[] = { 0U };    const unsigned short *portlistpnt = portlist;# endif    int on;    # ifndef NON_ROOT_FTP#  ifndef HAVE_SYS_FSUID_H    disablesignals();    seteuid((uid_t) 0);#  endif# endif        if ((datafd = socket(protocol, SOCK_STREAM, IPPROTO_TCP)) == -1) {        data_socket_error:# ifndef NON_ROOT_FTP#  ifndef HAVE_SYS_FSUID_H        if (seteuid(authresult.uid) != 0) {            _EXIT(EXIT_FAILURE);        }        enablesignals();#  endif# endif        (void) close(datafd);        datafd = -1;        error(425, MSG_CANT_CREATE_DATA_SOCKET);                return -1;    }    on = 1;# ifdef SO_REUSEPORT    (void) setsockopt(datafd, SOL_SOCKET, SO_REUSEPORT,                      (char *) &on, sizeof on);    # else    (void) setsockopt(datafd, SOL_SOCKET, SO_REUSEADDR,                      (char *) &on, sizeof on);# endif    memcpy(&dataconn, &ctrlconn, sizeof dataconn);    for (;;) {        if (STORAGE_FAMILY(dataconn) == AF_INET6) {            STORAGE_PORT6(dataconn) = htons(*portlistpnt);        } else {            STORAGE_PORT(dataconn) = htons(*portlistpnt);        }        if (bind(datafd, (struct sockaddr *) &dataconn,                  STORAGE_LEN(dataconn)) == 0) {            break;        }# ifdef USE_ONLY_FIXED_DATA_PORT        (void) sleep(1U);# else        if (*portlistpnt == (unsigned short) 0U) {            goto data_socket_error;        }        portlistpnt++;# endif    }# ifndef NON_ROOT_FTP#  ifndef HAVE_SYS_FSUID_H    if (seteuid(authresult.uid) != 0) {        _EXIT(EXIT_FAILURE);    }    enablesignals();#  endif# endif        return 0;}#else/* Privilege-separated version of doport3() */static int doport3(const int protocol){    if ((datafd = privsep_bindresport(protocol, ctrlconn)) == -1) {        error(425, MSG_CANT_CREATE_DATA_SOCKET);                return -1;    }    return 0;}#endifvoid doport2(struct sockaddr_storage a, unsigned int p){    if (loggedin == 0) {        addreply_noformat(530, MSG_NOT_LOGGED_IN);        return;    }    if (epsv_all != 0) {        addreply_noformat(501, MSG_ACTIVE_DISABLED);        return;    }    if (datafd != -1) {    /* for buggy clients saying PORT over and over */        (void) close(datafd);        datafd = -1;    }    if (p < 1024U) {        addreply_noformat(501, MSG_BAD_PORT);        return;    }    if (doport3(STORAGE_FAMILY(a) == AF_INET6 ? PF_INET6 : PF_INET) != 0) {        return;    }    peerdataport = (unsigned short) p;    if (addrcmp(&a, &peer) != 0) {        char hbuf[NI_MAXHOST];        char peerbuf[NI_MAXHOST];        if (getnameinfo((struct sockaddr *) &a, STORAGE_LEN(a),                        hbuf, sizeof hbuf, NULL,                        (size_t) 0U, NI_NUMERICHOST) != 0 ||            getnameinfo((struct sockaddr *) &peer, STORAGE_LEN(peer),                        peerbuf, sizeof peerbuf, NULL,                        (size_t) 0U, NI_NUMERICHOST) != 0) {            goto hu;        }        if (allowfxp == 0 || (allowfxp == 1 && guest != 0)) {            hu:            (void) close(datafd);            datafd = -1;            addreply(500, MSG_NO_FXP, hbuf, peerbuf);            return;        } else {            addreply(0, MSG_FXP, peerbuf, hbuf);            memcpy(&peer, &a, sizeof a);        }    }    passive = 0;    addreply_noformat(200, MSG_PORT_SUCCESSFUL);    return;}void closedata(void){    volatile int tmp_xferfd = xferfd;   /* do not simplify this... */        xferfd = -1;	       /* ...it avoids a race */    (void) close(tmp_xferfd);}void opendata(void){    struct sockaddr_storage dataconn;    /* his data connection endpoint */    int fd;    socklen_t socksize;    if (xferfd != -1) {	closedata();    }    if (datafd == -1) {        addreply_noformat(425, MSG_NO_DATA_CONN);                return;    }    if (passive != 0) {        fd_set rs;        struct timeval tv;        alarm(idletime);        for (;;) {            FD_ZERO(&rs);            FD_SET(datafd, &rs);            tv.tv_sec = idletime;            tv.tv_usec = 0;            /* I suppose it would be better to listen for ABRT too... */            if (select(datafd + 1, &rs, NULL, NULL, &tv) <= 0) {                die(421, LOG_INFO, MSG_TIMEOUT_DATA ,                     (unsigned long) idletime);            }            socksize = (socklen_t) sizeof(dataconn);            memset(&dataconn, 0, sizeof dataconn);            if ((fd = accept(datafd, (struct sockaddr *) &dataconn,                             &socksize)) == -1) {                nope:                (void) close(datafd);                datafd = -1;                error(421, MSG_ACCEPT_FAILED);                return;            }            if (STORAGE_FAMILY(dataconn) != AF_INET                && STORAGE_FAMILY(dataconn) != AF_INET6) {                (void) close(fd);                goto nope;            }            fourinsix(&dataconn);            if (addrcmp(&peer, &dataconn) == 0) {                break;            }            if (allowfxp == 0 || (allowfxp == 1 && guest != 0)) {                shutdown(fd, 2);                (void) close(fd);            } else {                break;            }        }        addreply_noformat(150, MSG_ACCEPT_SUCCESS);    } else {        struct sockaddr_storage peer2;        unsigned long tries = 1UL + idletime / 2UL;        peer2 = peer;        if (STORAGE_FAMILY(peer) == AF_INET6) {            STORAGE_PORT6(peer2) = htons(peerdataport);        } else {            STORAGE_PORT(peer2) = htons(peerdataport);        }        again:        if (connect(datafd, (struct sockaddr *) &peer2,                    STORAGE_LEN(peer2)) != 0) {            if ((errno == EAGAIN || errno == EINTR#ifdef EADDRINUSE                 || errno == EADDRINUSE#endif                 ) && tries > 0UL) {                tries--;                usleep2(1000000UL);                goto again;            }            addreply(425, MSG_CNX_PORT_FAILED ": %s",                     peerdataport, strerror(errno));            (void) close(datafd);            datafd = -1;            return;        }        fd = datafd;        datafd = -1;        addreply(150, MSG_CNX_PORT, peerdataport);    }    {        int fodder;#ifdef IPTOS_THROUGHPUT        fodder = IPTOS_THROUGHPUT;        setsockopt(fd, SOL_IP, IP_TOS, (char *) &fodder, sizeof fodder);#endif#ifndef NO_TCP_NOPUSH# ifdef TCP_NOPUSH        fodder = 1;        setsockopt(fd, SOL_TCP, TCP_NOPUSH, (char *) &fodder, sizeof fodder);# endif#endif#ifndef NO_TCP_LARGE_WINDOW#if defined(SO_SNDBUF) || defined(SO_RCVBUF)        fodder = 65536;#endif#ifdef SO_SNDBUF        setsockopt(fd, SOL_SOCKET, SO_SNDBUF, (char *) &fodder, sizeof fodder);#endif        #ifdef SO_RCVBUF        setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (char *) &fodder, sizeof fodder);#endif        #endif#ifndef NO_KEEPALIVE        keepalive(fd, 1);#endif    }    xferfd = fd;}#ifndef MINIMALvoid dochmod(char *name, mode_t mode){    static dev_t root_st_dev;    static ino_t root_st_ino;    struct stat st2;    int fd = -1;    if (nochmod != 0 && authresult.uid != (uid_t) 0) {        addreply(550, MSG_CHMOD_FAILED, name);        return;    }# ifndef ANON_CAN_CHANGE_PERMS    if (guest != 0) {        addreply_noformat(550, MSG_ANON_CANT_CHANGE_PERMS);        return;    }# endif    if (name == NULL || *name == 0) {        addreply_noformat(501, MSG_NO_FILE_NAME);        return;    }    if (checknamesanity(name, dot_write_ok) != 0) {        addreply(550, MSG_SANITY_FILE_FAILURE, name);        return;    }    fd = open(name, O_RDONLY);    if (fd == -1) {        goto failure;    }    if ((root_st_dev | root_st_ino) == 0) {        struct stat st;        if (stat("/", &st) != 0) {            goto failure;        }        root_st_dev = st.st_dev;        root_st_ino = st.st_ino;    }    if (fstat(fd, &st2) != 0) {        goto failure;    }# ifdef QUOTAS    if (hasquota() == 0 && S_ISDIR(st2.st_mode)) {        mode |= 0500;    }# endif    if (st2.st_ino == root_st_ino && st2.st_dev == root_st_dev) {        mode |= 0700;    } else if (be_customer_proof != 0) {        mode |= (S_ISDIR(st2.st_mode) ? 0700 : 0600);    }    if (fchmod(fd, mode) < 0 && chmod(name, mode) < 0) {        (void) close(fd);        failure:        if (fd != -1) {            (void) close(fd);        }        addreply(550, MSG_CHMOD_FAILED ": %s", name, strerror(errno));        return;    }    (void) close(fd);    addreply(200, MSG_CHMOD_SUCCESS, name);}#endifvoid dodele(char *name){#ifndef ANON_CAN_DELETE    if (guest != 0) {        addreply_noformat(550, MSG_ANON_CANT_DELETE);        return;    }#endif    if (name == NULL || *name == 0) {        addreply_noformat(501, MSG_NO_FILE_NAME);        return;    }    if (checknamesanity(name, dot_write_ok) != 0) {        addreply(550, MSG_SANITY_FILE_FAILURE, name);        return;    }    if (keepallfiles != 0) {#ifdef EPERM        errno = EPERM;#else        errno = 1;#endif        goto denied;    }    /*     * What we do here may look a bit strange. It's to defend against     * change-after-stat attacks. If we simply do lstat(name), then unlink(name)     * there's a race. An attacker can rename the file between these two     * system calls, so that a big file is lstat()ed, but a dummy tiny file is     * unlinked. That way, an attacker could easily get extra quota.     * To defend against this attack, we rename the file to an unique dot-file     * (an atomic operation) . People subject to quotas can't access dot-files.     * So we can securely stat it and unlink it. Having the pid in the 

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -