]> git.sesse.net Git - betaftpd/blobdiff - ftpd.c
Fixed a problem where the server might segfault if there was an error occuring while...
[betaftpd] / ftpd.c
diff --git a/ftpd.c b/ftpd.c
index d7f460621d8013a9d6cc08811093583e95cc4af0..23a7134e51665e384d598839ef28770e3faa95b1 100644 (file)
--- a/ftpd.c
+++ b/ftpd.c
 #include <stropts.h>
 #endif
 
+#if HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
 #if HAVE_SYS_CONF_H
 #include <sys/conf.h>
 #endif
 #include <unistd.h>
 #endif
 
-#if HAVE_ARPA_INET_H
-#include <arpa/inet.h>
-#endif
-
-#if HAVE_SYS_STAT_H
-#include <sys/stat.h>
-#endif
-
-#if HAVE_SYS_IOCTL_H
-#include <sys/ioctl.h>
-#endif
-
 #if HAVE_NETINET_IN_SYSTM_H
 #include <netinet/in_systm.h>
 #endif
 
+#if HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+
 #if HAVE_NETINET_IP_H
 #include <netinet/ip.h>
 #endif
 #include <netinet/tcp.h>
 #endif
 
+#if HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+
+#if HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+
+#if HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#endif
+
 #if HAVE_LINUX_SOCKET_H
 #include <linux/socket.h>
 #endif
@@ -176,6 +184,7 @@ struct ftran *first_ftran = NULL;
 #if WANT_DCACHE
 struct dcache *first_dcache = NULL;
 #endif
+char message_buf[512];
 
 #if HAVE_POLL
 unsigned int highest_fds = 0;
@@ -194,7 +203,7 @@ fd_set master_fds, master_send_fds;
 FILE *xferlog = NULL;
 #endif
 
-#if HAVE_LINUX_SENDFILE
+#if HAVE_LINUX_SENDFILE || HAVE_BSD_SENDFILE
 int sendfile_supported = 1;
 #endif
 
@@ -357,7 +366,7 @@ struct conn *alloc_new_conn(const int sock)
        const unsigned int one = 1;
        struct conn *c = (struct conn *)(malloc(sizeof(struct conn)));
 
-       if (c == NULL) return c;
+       if (c == NULL) return NULL;
 
        if (sock != -1) {
                ioctl(sock, FIONBIO, &one);
@@ -382,6 +391,7 @@ struct conn *alloc_new_conn(const int sock)
 #if WANT_ASCII
        c->ascii_mode = 0;
 #endif
+       c->free_me = 0;
 
        /*
         * equals:
@@ -398,7 +408,7 @@ struct conn *alloc_new_conn(const int sock)
 
        time(&(c->last_transfer));
 
-       /*list_clients();*/
+       /* list_clients(); */
 
        return c;
 }
@@ -588,7 +598,12 @@ int process_all_clients(const fd_set * const active_clients, const int num_ac)
  */
 void finish_transfer(struct ftran * const f)
 {
-       numeric(f->owner, 226, "Transfer complete.");
+       char finished[] = "226 Transfer complete.\r\n";
+               if (send(f->owner->sock, finished, sizeof(finished), 0) == -1 && errno == EPIPE) {
+               destroy_conn(f->owner);
+               return;
+       }
+       
        time(&(f->owner->last_transfer));
 
 #if WANT_XFERLOG
@@ -617,15 +632,14 @@ int process_all_sendfiles(fd_set * const active_clients, const int num_ac)
 {
        struct ftran *f = NULL, *next = first_ftran->next_ftran;
        int checked_through = 0;
-       struct sockaddr tempaddr;
-       int tempaddr_len = sizeof(tempaddr);
+       int tempaddr_len = sizeof(struct sockaddr_in);
  
        while (next != NULL && checked_through < num_ac) {
                f = next;
                next = f->next_ftran;
 
-#if HAVE_UPLOAD
-               if (f->upload == 1 && fds[f->sock].revents & POLLHUP) {
+#if WANT_UPLOAD
+               if ((f->upload == 1) && (fds[f->sock].revents & POLLHUP)) {
                        finish_transfer(f);
                        continue;
                }
@@ -657,8 +671,7 @@ int process_all_sendfiles(fd_set * const active_clients, const int num_ac)
 
                if (f->state == 2) {            /* incoming PASV */
                        const unsigned int one = 1;
-                       const int tempsock = accept(f->sock, (struct sockaddr *)&tempaddr,
-                                                       &tempaddr_len);
+                       const int tempsock = accept(f->sock, &(f->sin), &tempaddr_len);
 
                        del_fd(f->sock);
 
@@ -760,7 +773,7 @@ int do_download(struct ftran *f)
 #endif
        int size;
 
-#if HAVE_LINUX_SENDFILE
+#if HAVE_LINUX_SENDFILE || HAVE_BSD_SENDFILE
        /*
         * We handle the optimal case first, which is sendfile().
         * Here we use a rather simplified sending `algorithm',
@@ -779,7 +792,7 @@ int do_download(struct ftran *f)
                }       
 #endif
 
-                       err = sendfile(f->sock, f->local_file, &f->pos, size);
+                       err = mysendfile(f->sock, f->local_file, &f->pos, size);
                return (f->pos < f->size) && (err > -1);
        }
 #endif
@@ -839,11 +852,11 @@ void write_xferlog(struct ftran *f)
 
        if (xferlog == NULL) return;
 
-       strftime(temp, 256, "%a %b %d %H:%M:%S %Y", t);
+       strftime(temp, 256, "%a  %b %d %H:%M:%S %Y", t);
 #if WANT_UPLOAD
-       fprintf(xferlog, "%s %u %s %lu %s b _ %c a %s ftp 0 * \n",
+       fprintf(xferlog, "%s %u %s %lu %s b _ %c %c %s ftp 0 *\n",
 #else
-       fprintf(xferlog, "%s %u %s %lu %s b _ o a %s ftp 0 *\n",
+       fprintf(xferlog, "%s %u %s %lu %s b _ o %c %s ftp 0 *\n",
 #endif
                temp, (int)(difftime(now, f->tran_start)),
                inet_ntoa(f->sin.sin_addr), f->size,
@@ -851,7 +864,7 @@ void write_xferlog(struct ftran *f)
 #if WANT_UPLOAD
                (f->upload) ? 'i' : 'o',
 #endif
-               f->owner->username);
+               (f->owner->auth == 4) ? 'r' : 'a', f->owner->username);
                fflush(xferlog);
 
 #if 0
@@ -944,8 +957,8 @@ int main(void)
 #warning No xferlog support for nonroot yet
 #else
        /* open xferlog */
-       xferlog = fopen("/var/log/xferlog", "r+");
-       if (xferlog == NULL) xferlog = fopen("/usr/adm/xferlog", "r+");
+       xferlog = fopen("/var/log/xferlog", "a");
+       if (xferlog == NULL) xferlog = fopen("/usr/adm/xferlog", "a");
 
        if (xferlog != NULL) {
                  fseek(xferlog, 0L, SEEK_END);
@@ -973,7 +986,7 @@ int main(void)
        alarm(60);
        signal(SIGALRM, handle_alarm);
 
-#if HAVE_LINUX_SENDFILE
+#if HAVE_LINUX_SENDFILE || HAVE_BSD_SENDFILE
        /* check that sendfile() is really implemented (same check as configure does) */
        {
                int out_fd = 1, in_fd = 0;
@@ -981,7 +994,7 @@ int main(void)
                size_t size = 1024;
 
                errno = 0;
-               sendfile(out_fd, in_fd, &offset, size);
+               mysendfile(out_fd, in_fd, &offset, size);
                if (errno == ENOSYS) sendfile_supported = 0;
        }
 #endif
@@ -1111,10 +1124,14 @@ void accept_new_client(int * const server_sock)
                struct conn * const c = alloc_new_conn(tempsock);
                num_err = 0;
                if (c != NULL) {
-                       numeric(c, 220, "BetaFTPD " VERSION " ready.");
+                       char hello[] = "220 BetaFTPD " VERSION " ready.\r\n";
+                       
 #if WANT_STAT
                        memcpy(&(c->addr), &tempaddr, sizeof(struct sockaddr));
 #endif
+
+                       if (send(tempsock, hello, sizeof(hello), 0) == -1 && errno == EPIPE)
+                               destroy_conn(c);
                }
        }
 }
@@ -1186,23 +1203,26 @@ void remove_bytes(struct conn * const c, const int num)
  *             you can use this command much the same way as you
  *             would use a printf() (with all the normal %s, %d,
  *             etc.), since it actually uses printf() internally.
+ *
+ *             This command doesn't actually SEND the data -- it
+ *             just puts it in a buffer which is sent after the
+ *             command handler has completed. The reasons for this
+ *             are simple -- it makes error checking and cleanup
+ *             MUCH cleaner, so we won't have to check for errors
+ *             in every single little branch of the code.
  */
 void numeric(struct conn * const c, const int numeric, const char * const format, ...)
 {
-       char buf[256], fmt[256];
+       char fmt[256];
        va_list args;
        int i, err;
+       int in_buf = strlen(message_buf);
 
        snprintf(fmt, 256, "%03u %s\r\n", numeric, format);
 
        va_start(args, format);
-       i = vsnprintf(buf, 256, fmt, args);
+       i = vsnprintf(message_buf + in_buf, 512 - in_buf, fmt, args);
        va_end(args);
-
-       err = send(c->sock, buf, i, 0);
-       if (err == -1 && errno == EPIPE) {
-               destroy_conn(c);
-       }
 }
 
 /*
@@ -1338,7 +1358,7 @@ void init_file_transfer(struct ftran * const f)
         */
 #if HAVE_MMAP
        if (f->dir_listing == 0) {
-#if HAVE_LINUX_SENDFILE
+#if HAVE_LINUX_SENDFILE || HAVE_BSD_SENDFILE
                int do_mmap = (sendfile_supported) ? 0 : 1;
 #else
                int do_mmap = 1;
@@ -1481,6 +1501,24 @@ void clear_bad_fds(int * const server_sock)
 }
 #endif
 
+#if HAVE_BSD_SENDFILE || HAVE_LINUX_SENDFILE
+int mysendfile(int sock, int fd, off_t *offset, size_t count)
+{
+#if HAVE_BSD_SENDFILE
+       int err;
+       off_t ssize = 0;
+       
+       err = sendfile(fd, sock, *offset, count, NULL, &ssize, 0);
+       if (ssize > 0) *offset += ssize;
+#else /* !HAVE_BSD_SENDFILE */
+#if HAVE_LINUX_SENDFILE
+       return sendfile(sock, fd, offset, count);
+#endif /* HAVE_LINUX_SENDFILE */
+#endif /* !HAVE_BSD_SENDFILE */
+}
+#endif /* HAVE_BSD_SENDFILE || HAVE_LINUX_SENDFILE */
+
+
 #if WANT_MESSAGE
 /*
  * dump_file(): Dumps a file on the control connection. Used for