Submitted By: Mario Fetka (geos_one) (mario dot fetka at gmail dot com) Date: 2010-01-05 Initial Package Version: 0.3.6 Origin: ftp://ftp.deepspace6.net/pub/ds6/sources/oftpd/oftpd-0.3.6-ipv6rel2.patch.gz Upstream Status: unknown Description: add better ipv6 support to oftpd diff -Naur oftpd-0.3.7.orig/src/Makefile.am oftpd-0.3.7/src/Makefile.am --- oftpd-0.3.7.orig/src/Makefile.am 2001-04-17 23:05:16.000000000 +0000 +++ oftpd-0.3.7/src/Makefile.am 2010-01-05 21:50:11.109303546 +0000 @@ -1,2 +1,2 @@ bin_PROGRAMS = oftpd -oftpd_SOURCES = file_list.c file_list.h ftp_command.c ftp_command.h ftp_listener.c ftp_listener.h ftp_session.c ftp_session.h oftpd.c oftpd.h telnet_session.c telnet_session.h watchdog.c watchdog.h error.c error.h af_portability.h daemon_assert.c daemon_assert.h +oftpd_SOURCES = file_list.c file_list.h ftp_command.c ftp_command.h ftp_listener.c ftp_listener.h ftp_session.c ftp_session.h oftpd.c oftpd.h telnet_session.c telnet_session.h watchdog.c watchdog.h error.c error.h af_portability.h af_portability.c daemon_assert.c daemon_assert.h diff -Naur oftpd-0.3.7.orig/src/af_portability.c oftpd-0.3.7/src/af_portability.c --- oftpd-0.3.7.orig/src/af_portability.c 1970-01-01 00:00:00.000000000 +0000 +++ oftpd-0.3.7/src/af_portability.c 2010-01-05 21:50:11.109303546 +0000 @@ -0,0 +1,32 @@ +#include +#include +#include + +unsigned short int sockaddr_port(const struct sockaddr *sa, socklen_t salen) +{ +#ifdef INET6 + char sbuf[NI_MAXSERV]; +#endif + unsigned short int port = 0; + +#ifdef INET6 + if (getnameinfo(sa, salen, NULL, 0, sbuf, sizeof(sbuf), + NI_NUMERICSERV) == 0) + port = atoi(sbuf); + else +#endif + switch (sa->sa_family) { + case AF_INET: + port = ntohs(((struct sockaddr_in *)sa)->sin_port); + break; +#ifdef INET6 + case AF_INET6: + port = ntohs(((struct sockaddr_in6 *)sa)->sin6_port); + break; +#endif + default: + /* everything went wrong :-P */ + exit(1); + } + return port; +} diff -Naur oftpd-0.3.7.orig/src/af_portability.h oftpd-0.3.7/src/af_portability.h --- oftpd-0.3.7.orig/src/af_portability.h 2001-03-28 22:31:01.000000000 +0000 +++ oftpd-0.3.7/src/af_portability.h 2010-01-05 21:50:11.109303546 +0000 @@ -2,10 +2,9 @@ #define AF_PORTABILITY_H #include -#include /* _x_ must be a pointer to a sockaddr structure */ - +/* #define SAFAM(_x_) (((struct sockaddr *)(_x_))->sa_family) #ifdef HAVE_NEW_SS_FAMILY @@ -26,6 +25,7 @@ #define SINADDR(_x_) SIN4ADDR(_x_) #define SINPORT(_x_) SIN4PORT(_x_) #endif +*/ #ifndef INET_ADDRSTRLEN #define INET_ADDRSTRLEN 16 @@ -43,10 +43,13 @@ #define IP_ADDRSTRLEN INET_ADDRSTRLEN #endif +unsigned short int sockaddr_port(const struct sockaddr *sa, socklen_t salen); +/* #ifdef INET6 typedef struct sockaddr_storage sockaddr_storage_t; #else typedef struct sockaddr_in sockaddr_storage_t; #endif +*/ #endif /* AF_PORTABILITY_H */ diff -Naur oftpd-0.3.7.orig/src/config.h.in oftpd-0.3.7/src/config.h.in --- oftpd-0.3.7.orig/src/config.h.in 2002-02-04 22:45:58.000000000 +0000 +++ oftpd-0.3.7/src/config.h.in 2010-01-05 21:50:11.110304366 +0000 @@ -97,15 +97,15 @@ /* Define if you have the header file. */ #undef HAVE_LIMITS_H +/* Define if you have the header file. */ +#undef HAVE_SYSLOG_H + /* Define if you have the header file. */ #undef HAVE_SYS_TIME_H /* Define if you have the header file. */ #undef HAVE_SYS_TYPES_H -/* Define if you have the header file. */ -#undef HAVE_SYSLOG_H - /* Define if you have the header file. */ #undef HAVE_UNISTD_H diff -Naur oftpd-0.3.7.orig/src/error.c oftpd-0.3.7/src/error.c --- oftpd-0.3.7.orig/src/error.c 2001-04-18 21:41:04.000000000 +0000 +++ oftpd-0.3.7/src/error.c 2010-01-05 21:50:11.110304366 +0000 @@ -23,6 +23,7 @@ { va_list args; + fprintf(stderr, "error_init: %d %s", error_code, desc_fmt); daemon_assert(err != NULL); daemon_assert(error_code >= 0); daemon_assert(desc_fmt != NULL); diff -Naur oftpd-0.3.7.orig/src/ftp_command.c oftpd-0.3.7/src/ftp_command.c --- oftpd-0.3.7.orig/src/ftp_command.c 2004-03-25 20:46:57.000000000 +0000 +++ oftpd-0.3.7/src/ftp_command.c 2010-01-05 21:50:11.133303657 +0000 @@ -12,7 +12,6 @@ #include #include #include "ftp_command.h" -#include "af_portability.h" #include "daemon_assert.h" /* argument types */ @@ -67,8 +66,8 @@ static const char *parse_host_port(struct sockaddr_in *addr, const char *s); static const char *parse_number(int *num, const char *s, int max_num); static const char *parse_offset(off_t *ofs, const char *s); -static const char *parse_host_port_long(sockaddr_storage_t *sa, const char *s); -static const char *parse_host_port_ext(sockaddr_storage_t *sa, const char *s); +static const char *parse_host_port_long(struct sockaddr *sa, const char *s); +static const char *parse_host_port_ext(struct sockaddr *sa, const char *s); int ftp_command_parse(const char *input, ftp_command_t *cmd) { @@ -137,7 +136,7 @@ input++; /* parse the host & port information (if any) */ - input = parse_host_port(&tmp.arg[0].host_port, input); + input = parse_host_port((struct sockaddr_in *)&tmp.arg[0].host_port, input); if (input == NULL) { return 0; } @@ -151,7 +150,7 @@ input++; /* parse the host & port information (if any) */ - input = parse_host_port_long(&tmp.arg[0].host_port, input); + input = parse_host_port_long((struct sockaddr *)&tmp.arg[0].host_port, input); if (input == NULL) { return 0; } @@ -165,7 +164,7 @@ input++; /* parse the host & port information (if any) */ - input = parse_host_port_ext(&tmp.arg[0].host_port, input); + input = parse_host_port_ext((struct sockaddr *)&tmp.arg[0].host_port, input); if (input == NULL) { return 0; } @@ -378,7 +377,7 @@ /* note: returns success even for unknown address families */ /* this is okay, as long as subsequent uses VERIFY THE FAMILY first */ -static const char *parse_host_port_long(sockaddr_storage_t *sa, const char *s) +static const char *parse_host_port_long(struct sockaddr *sa, const char *s) { int i; int family; @@ -441,38 +440,38 @@ /* okay, everything parses, load the address if possible */ if (family == 4) { - SAFAM(sa) = AF_INET; + ((struct sockaddr_in *)sa)->sin_family = AF_INET; if (addr_len != sizeof(struct in_addr)) { return NULL; } if (port_len != 2) { return NULL; - } - memcpy(&SINADDR(sa), addr, addr_len); - SINPORT(sa) = htons((port[0] << 8) + port[1]); + } + memcpy(&((struct sockaddr_in *)sa)->sin_addr, addr, addr_len); + ((struct sockaddr_in *)sa)->sin_port = htons((port[0] << 8) + port[1]); } #ifdef INET6 else if (family == 6) { - SAFAM(sa) = AF_INET6; + ((struct sockaddr_in6 *)sa)->sin6_family = AF_INET6; if (addr_len != sizeof(struct in6_addr)) { return NULL; } if (port_len != 2) { return NULL; } - memcpy(&SIN6ADDR(sa), addr, addr_len); - SINPORT(sa) = htons((port[0] << 8) + port[1]); + memcpy(&((struct sockaddr_in6 *)sa)->sin6_addr, addr, addr_len); + ((struct sockaddr_in6 *)sa)->sin6_port = htons((port[0] << 8) + port[1]); } #endif else { - SAFAM(sa) = -1; + sa->sa_family = -1; } /* return new pointer */ return s; } -static const char *parse_host_port_ext(sockaddr_storage_t *sa, const char *s) +static const char *parse_host_port_ext(struct sockaddr *sa, const char *s) { int delimeter; int family; @@ -545,12 +544,11 @@ } #endif /* HAVE_INET_ATON */ - SIN4ADDR(sa) = in_addr; + ((struct sockaddr_in *)sa)->sin_addr = in_addr; } #else { - struct addrinfo hints; - struct *res; + struct addrinfo hints, *res; memset(&hints, 0, sizeof(hints)); hints.ai_flags = AI_NUMERICHOST; @@ -566,8 +564,17 @@ } #endif /* INET6 */ - SAFAM(sa) = family; - SINPORT(sa) = htons(port); + sa->sa_family = family; + if (family == AF_INET) { + ((struct sockaddr_in *)sa)->sin_port = htons(port); +#ifdef INET6 + } else if (family == AF_INET6) { + ((struct sockaddr_in6 *)sa)->sin6_port = htons(port); +#endif /* INET6 */ + } else { + /* we have an error! */ + return NULL; + } /* return new pointer */ return s; diff -Naur oftpd-0.3.7.orig/src/ftp_command.h oftpd-0.3.7/src/ftp_command.h --- oftpd-0.3.7.orig/src/ftp_command.h 2001-03-20 23:56:00.000000000 +0000 +++ oftpd-0.3.7/src/ftp_command.h 2010-01-05 21:50:11.141303856 +0000 @@ -34,7 +34,6 @@ #include #include #include -#include "af_portability.h" /* special macro for handling EPSV ALL requests */ #define EPSV_ALL (-1) @@ -50,7 +49,11 @@ int num_arg; union { char string[MAX_STRING_LEN+1]; - sockaddr_storage_t host_port; +#ifdef INET6 + struct sockaddr_storage host_port; +#else + struct sockaddr_in host_port; +#endif int num; off_t offset; } arg[MAX_ARG]; diff -Naur oftpd-0.3.7.orig/src/ftp_listener.c oftpd-0.3.7/src/ftp_listener.c --- oftpd-0.3.7.orig/src/ftp_listener.c 2001-05-10 23:29:46.000000000 +0000 +++ oftpd-0.3.7/src/ftp_listener.c 2010-01-05 21:50:11.144303870 +0000 @@ -52,7 +52,6 @@ #include "af_portability.h" - /* maximum number of consecutive errors in accept() before we terminate listener */ #define MAX_ACCEPT_ERROR 10 @@ -73,7 +72,7 @@ /* prototypes */ static int invariant(const ftp_listener_t *f); static void *connection_acceptor(ftp_listener_t *f); -static void addr_to_string(const sockaddr_storage_t *s, char *addr); +static void addr_to_string(const struct sockaddr *s, char *addr); static void *connection_handler(connection_info_t *info); static void connection_handler_cleanup(connection_info_t *info); @@ -85,14 +84,22 @@ int inactivity_timeout, error_t *err) { - sockaddr_storage_t sock_addr; +#ifdef INET6 + struct sockaddr_storage sock_addr; + int gai_err; + struct addrinfo hints; + struct addrinfo *res; + char buf[ADDR_BUF_LEN+1]; + int ret; +#else + struct sockaddr_in sock_addr; + char *addr_str; +#endif int fd; int flags; int pipefds[2]; int reuseaddr; char dir[PATH_MAX+1]; - char buf[ADDR_BUF_LEN+1]; - const char *inet_ntop_ret; daemon_assert(f != NULL); daemon_assert(port >= 0); @@ -108,64 +115,67 @@ } /* set up our socket address */ - memset(&sock_addr, 0, sizeof(sockaddr_storage_t)); + memset(&sock_addr, 0, sizeof(sock_addr)); - if (address == NULL) { #ifdef INET6 - SAFAM(&sock_addr) = AF_INET6; - memcpy(&SIN6ADDR(&sock_addr), &in6addr_any, sizeof(struct in6_addr)); + memset(&hints, 0, sizeof(hints)); + + /* with AF_UNSPEC we can handle even hostnames */ + hints.ai_family = (address == NULL ? AF_INET6 : AF_UNSPEC); + hints.ai_flags = AI_PASSIVE; + hints.ai_socktype = SOCK_STREAM; + + gai_err = getaddrinfo(address, "21", &hints, &res); + if (gai_err != 0) { + if (gai_err < 0) gai_err = -gai_err; + error_init(err, gai_err, "error parsing server socket address; %s", + gai_strerror(gai_err)); + return 0; + } + + memcpy(&sock_addr, res->ai_addr, res->ai_addrlen); + freeaddrinfo(res); #else - SAFAM(&sock_addr) = AF_INET; + if (address == NULL) { + sock_addr.sin_family = AF_INET; sock_addr.sin_addr.s_addr = INADDR_ANY; -#endif } else { - int gai_err; - struct addrinfo hints; - struct addrinfo *res; - - memset(&hints, 0, sizeof(hints)); - -/* - This code should be able to parse both IPv4 and IPv6 internet - * addresses and put them in the sock_addr variable. - * - Much neater now. - * - Bug: Can't handle hostnames, only IP addresses. Not sure - * exactly why. But then again, I'm not sure exactly why - * there is a man page for getipnodebyname (which getaddrinfo - * says it uses) but no corresponding function in libc. - * -- Matthew Danish [3/20/2001] - */ + struct hostent *hp; + + hp = gethostbyname(address); + if(hp == NULL) { + error_init(err, h_errno, "error with gethostbyname"); + return 0; + } + + assert(hp->h_length <= sizeof(sock_addr)); + memcpy(&sock_addr, hp->h_addr, hp->h_length); + } +#endif + /* setup non-default port */ + if (port != 0) { + sa_family_t family = ((struct sockaddr *)&sock_addr)->sa_family; + switch (family) { #ifdef INET6 - hints.ai_family = AF_INET6; -#else - hints.ai_family = AF_INET; + case AF_INET6: + ((struct sockaddr_in6*)&sock_addr)->sin6_port = port; + break; #endif - - hints.ai_flags = AI_PASSIVE; - - gai_err = getaddrinfo(address, NULL, &hints, &res); - if (gai_err != 0) { - error_init(err, gai_err, "error parsing server socket address; %s", - gai_strerror(gai_err)); - return 0; - } - - memcpy(&sock_addr, res->ai_addr, res->ai_addrlen); - freeaddrinfo(res); - } - - if (port == 0) { - SINPORT(&sock_addr) = htons(DEFAULT_FTP_PORT); - } else { - SINPORT(&sock_addr) = htons(port); + case AF_INET: + ((struct sockaddr_in*)&sock_addr)->sin_port = port; + break; + default: + /* handle error */ + error_init(err, 1, "unknown adderess family"); + return 0; + } } - - - inet_ntop_ret = inet_ntop(SAFAM(&sock_addr), - (void *)&SINADDR(&sock_addr), - buf, - sizeof(buf)); - if (inet_ntop_ret == NULL) { + +#ifdef INET6 + ret = getnameinfo((struct sockaddr *)(&sock_addr), sizeof(sock_addr), buf, sizeof(buf), + NULL, 0, NI_NUMERICHOST); + if (ret != 0) { error_init(err, errno, "error converting server address to ASCII; %s", strerror(errno)); return 0; @@ -173,11 +183,26 @@ /* Put some information in syslog */ syslog(LOG_INFO, "Binding interface '%s', port %d, max clients %d\n", buf, - ntohs(SINPORT(&sock_addr)), max_connections); + sockaddr_port((struct sockaddr *)&sock_addr, sizeof(sock_addr)), max_connections); +#else + /* this should be thread-safe, as glibc texinfo documentation states: + * + * In multi-threaded programs each thread has an own + * statically-allocated buffer (for inet_ntoa). But still + * subsequent calls of `inet_ntoa' in the same thread will + * overwrite the result of the last call. + */ + addr_str = inet_ntoa(sock_addr.sin_addr); + + /* Put some information in syslog */ + syslog(LOG_INFO, "Binding interface '%s', port %d, max clients %d\n", + addr_str,sockaddr_port((struct sockaddr*)&sock_addr,sizeof(sock_addr)), + max_connections); +#endif /* okay, finally do some socket manipulation */ - fd = socket(AF_INET, SOCK_STREAM, 0); + fd = socket(((struct sockaddr *)&sock_addr)->sa_family, SOCK_STREAM, 0); if (fd == -1) { error_init(err, errno, "error creating socket; %s", strerror(errno)); return 0; @@ -193,8 +218,7 @@ return 0; } - if (bind(fd, (struct sockaddr *)&sock_addr, - sizeof(struct sockaddr_in)) != 0) + if (bind(fd, (struct sockaddr *)&sock_addr, sizeof(sock_addr)) != 0) { close(fd); error_init(err, errno, "error binding address; %s", strerror(errno)); @@ -261,6 +285,8 @@ daemon_assert(invariant(f)); daemon_assert(err != NULL); + syslog(LOG_WARNING, "in ftp_listener_start\n"); + error_code = pthread_create(&thread_id, NULL, (void *(*)())connection_acceptor, @@ -320,8 +346,13 @@ int fd; int tcp_nodelay; - sockaddr_storage_t client_addr; - sockaddr_storage_t server_addr; +#ifdef INET6 + struct sockaddr_storage client_addr; + struct sockaddr_storage server_addr; +#else + struct sockaddr_in client_addr; + struct sockaddr_in server_addr; +#endif unsigned addr_len; connection_info_t *info; @@ -332,6 +363,8 @@ daemon_assert(invariant(f)); + syslog(LOG_WARNING, "in connection_acceptor\n"); + if (!watchdog_init(&f->watchdog, f->inactivity_timeout, &err)) { syslog(LOG_ERR, "Error initializing watchdog thread; %s", error_get_desc(&err)); @@ -355,10 +388,12 @@ } /* otherwise accept our pending connection (if any) */ - addr_len = sizeof(sockaddr_storage_t); + addr_len = sizeof(client_addr); fd = accept(f->fd, (struct sockaddr *)&client_addr, &addr_len); if (fd >= 0) { + syslog(LOG_WARNING, "in connection_acceptor loop\n"); + tcp_nodelay = 1; if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (void *)&tcp_nodelay, sizeof(int)) != 0) @@ -370,7 +405,7 @@ continue; } - addr_len = sizeof(sockaddr_storage_t); + addr_len = sizeof(server_addr); if (getsockname(fd, (struct sockaddr *)&server_addr, &addr_len) == -1) { @@ -392,9 +427,11 @@ telnet_session_init(&info->telnet_session, fd, fd); + syslog(LOG_WARNING, "about to call ftp_session_init\n"); + if (!ftp_session_init(&info->ftp_session, - &client_addr, - &server_addr, + (struct sockaddr *)&client_addr, + (struct sockaddr *)&server_addr, &info->telnet_session, f->dir, &err)) @@ -444,7 +481,7 @@ /* convert an address to a printable string */ /* NOT THREADSAFE - wrap with a mutex before calling! */ -static char *addr2string(const sockaddr_storage_t *s) +static char *addr2string(const struct sockaddr *s) { static char addr[IP_ADDRSTRLEN+1]; int error; @@ -454,14 +491,14 @@ #ifdef INET6 error = getnameinfo((struct sockaddr *)s, - sizeof(sockaddr_storage_t), + sizeof(struct sockaddr_storage), addr, sizeof(addr), NULL, 0, NI_NUMERICHOST); if (error != 0) { - syslog(LOG_WARN, "getnameinfo error; %s", gai_strerror(error)); + syslog(LOG_WARNING, "getnameinfo error; %s", gai_strerror(error)); ret_val = "Unknown IP"; } else { ret_val = addr; @@ -480,6 +517,7 @@ int num_connections; char drop_reason[80]; + syslog(LOG_WARNING, "in connection_handler\n"); /* for ease of use only */ f = info->ftp_listener; @@ -497,13 +535,15 @@ pthread_mutex_lock(&f->mutex); num_connections = ++f->num_connections; syslog(LOG_INFO, "%s port %d connection", - addr2string(&info->ftp_session.client_addr), - ntohs(SINPORT(&info->ftp_session.client_addr))); + addr2string((struct sockaddr *)&info->ftp_session.client_addr), + sockaddr_port((struct sockaddr *)&info->ftp_session.client_addr, + sizeof(info->ftp_session.client_addr))); pthread_mutex_unlock(&f->mutex); /* handle the session */ if (num_connections <= f->max_connections) { + syslog(LOG_WARNING, "about to call ftp_session_run\n"); ftp_session_run(&info->ftp_session, &info->watched); } else { @@ -518,8 +558,9 @@ pthread_mutex_lock(&f->mutex); syslog(LOG_WARNING, "%s port %d exceeds max users (%d), dropping connection", - addr2string(&info->ftp_session.client_addr), - ntohs(SINPORT(&info->ftp_session.client_addr)), + addr2string((struct sockaddr *)&info->ftp_session.client_addr), + sockaddr_port((struct sockaddr *)&info->ftp_session.client_addr, + sizeof(info->ftp_session.client_addr)), num_connections); pthread_mutex_unlock(&f->mutex); @@ -548,8 +589,9 @@ syslog(LOG_INFO, "%s port %d disconnected", - addr2string(&info->ftp_session.client_addr), - ntohs(SINPORT(&info->ftp_session.client_addr))); + addr2string((struct sockaddr *)&info->ftp_session.client_addr), + sockaddr_port((struct sockaddr *)&info->ftp_session.client_addr, + sizeof(info->ftp_session.client_addr))); pthread_mutex_unlock(&f->mutex); diff -Naur oftpd-0.3.7.orig/src/ftp_session.c oftpd-0.3.7/src/ftp_session.c --- oftpd-0.3.7.orig/src/ftp_session.c 2004-03-25 20:46:40.000000000 +0000 +++ oftpd-0.3.7/src/ftp_session.c 2010-01-05 21:50:11.159303450 +0000 @@ -52,12 +52,12 @@ static void init_passive_port(); static int get_passive_port(); static int convert_newlines(char *dst, const char *src, int srclen); -static void get_addr_str(const sockaddr_storage_t *s, char *buf, int bufsiz); +static void get_addr_str(const struct sockaddr *s, char *buf, int bufsiz); static void send_readme(const ftp_session_t *f, int code); static void netscape_hack(int fd); -static void set_port(ftp_session_t *f, const sockaddr_storage_t *host_port); -static int set_pasv(ftp_session_t *f, sockaddr_storage_t *host_port); -static int ip_equal(const sockaddr_storage_t *a, const sockaddr_storage_t *b); +static void set_port(ftp_session_t *f, const struct sockaddr *host_port); +static int set_pasv(ftp_session_t *f, struct sockaddr *host_port); +static int ip_equal(const struct sockaddr *a, const struct sockaddr *b); static void get_absolute_fname(char *fname, int fname_len, const char *dir, @@ -123,8 +123,8 @@ int ftp_session_init(ftp_session_t *f, - const sockaddr_storage_t *client_addr, - const sockaddr_storage_t *server_addr, + const struct sockaddr *client_addr, + const struct sockaddr *server_addr, telnet_session_t *t, const char *dir, error_t *err) @@ -138,9 +138,9 @@ daemon_assert(err != NULL); #ifdef INET6 - /* if the control connection is on IPv6, we need to get an IPv4 address */ - /* to bind the socket to */ - if (SSFAM(server_addr) == AF_INET6) { + /* if the control connection is on IPv6, we need to get an IPv4 address + * to bind the socket to */ + if (server_addr->sa_family == AF_INET6) { struct addrinfo hints; struct addrinfo *res; int errcode; @@ -149,8 +149,10 @@ memset(&hints, 0, sizeof(struct addrinfo)); hints.ai_family = AF_INET; hints.ai_flags = AI_PASSIVE; - if (getaddrinfo(NULL, "ftp", &hints, &res) != 0) { - error_init(err, 0, "unable to determing IPv4 address; %s", + hints.ai_socktype = SOCK_STREAM; + + if ((errcode = getaddrinfo(NULL, "21", &hints, &res)) != 0) { + error_init(err, 0, "unable to determine IPv4 address; %s", gai_strerror(errcode)); return 0; } @@ -158,17 +160,14 @@ /* let's sanity check */ daemon_assert(res != NULL); daemon_assert(sizeof(f->server_ipv4_addr) >= res->ai_addrlen); - daemon_assert(SSFAM(host_port) == AF_INET); + daemon_assert(res->ai_addr->sa_family == AF_INET); /* copy the result and free memory as necessary */ memcpy(&f->server_ipv4_addr, res->ai_addr, res->ai_addrlen); freeaddrinfo(res); } else { - daemon_assert(SSFAM(host_port) == AF_INET); - f->server_ipv4_addr = *server_addr; + f->server_ipv4_addr = *((struct sockaddr_in *)server_addr); } -#else - f->server_ipv4_addr = *server_addr; #endif f->session_active = 1; @@ -182,17 +181,22 @@ f->epsv_all_set = 0; - f->client_addr = *client_addr; +#ifdef INET6 + memcpy(&f->client_addr, client_addr, sizeof(struct sockaddr_in6)); + memcpy(&f->server_addr, server_addr, sizeof(struct sockaddr_in6)); + memcpy(&f->data_port, client_addr, sizeof(struct sockaddr_in6)); +#else + memcpy(&f->client_addr, client_addr, sizeof(struct sockaddr_in)); + memcpy(&f->server_addr, server_addr, sizeof(struct sockaddr_in)); + memcpy(&f->data_port, client_addr, sizeof(struct sockaddr_in)); +#endif get_addr_str(client_addr, f->client_addr_str, sizeof(f->client_addr_str)); - f->server_addr = *server_addr; - f->telnet_session = t; daemon_assert(strlen(dir) < sizeof(f->dir)); strcpy(f->dir, dir); f->data_channel = DATA_PORT; - f->data_port = *client_addr; f->server_fd = -1; daemon_assert(invariant(f)); @@ -326,7 +330,8 @@ /* If the client specifies a port, verify that it is from the */ /* host the client connected from. This prevents a client from */ /* using the server to open connections to arbritrary hosts. */ - if (!ip_equal(&f->client_addr, &f->data_port)) { + if (!ip_equal((struct sockaddr *)&f->client_addr, + (struct sockaddr *)&f->data_port)) { return 0; } if (f->server_fd != -1) { @@ -412,7 +417,7 @@ } #ifdef INET6 -static void get_addr_str(const sockaddr_storage_t *s, char *buf, int bufsiz) +static void get_addr_str(const struct sockaddr *s, char *buf, int bufsiz) { int port; int error; @@ -426,17 +431,17 @@ * number (which is 5 chars max), plus the '\0' character. */ daemon_assert(bufsiz >= (INET_ADDRSTRLEN + 12)); - error = getnameinfo(client_addr, sizeof(sockaddr_storage_t), buf, + error = getnameinfo(s, sizeof(struct sockaddr_storage), buf, bufsiz, NULL, 0, NI_NUMERICHOST); /* getnameinfo() should never fail when called with NI_NUMERICHOST */ daemon_assert(error == 0); len = strlen(buf); daemon_assert(bufsiz >= len+12); - snprintf(buf+len, bufsiz-len, " port %d", ntohs(SINPORT(&f->client_addr))); + snprintf(buf+len, bufsiz-len, " port %d", sockaddr_port((struct sockaddr *)s, sizeof(s))); } #else -static void get_addr_str(const sockaddr_storage_t *s, char *buf, int bufsiz) +static void get_addr_str(const struct sockaddr *s, char *buf, int bufsiz) { unsigned int addr; int port; @@ -449,8 +454,8 @@ * number (which is 5 chars max), plus the '\0' character. */ daemon_assert(bufsiz >= (INET_ADDRSTRLEN + 12)); - addr = ntohl(s->sin_addr.s_addr); - port = ntohs(s->sin_port); + addr = ntohl(((struct sockaddr_in *)s)->sin_addr.s_addr); + port = ntohs(((struct sockaddr_in *)s)->sin_port); snprintf(buf, bufsiz, "%d.%d.%d.%d port %d", (addr >> 24) & 0xff, (addr >> 16) & 0xff, @@ -626,16 +631,22 @@ } /* support for the various port setting functions */ -static void set_port(ftp_session_t *f, const sockaddr_storage_t *host_port) -{ +static void set_port(ftp_session_t *f, const struct sockaddr *host_port) +{ daemon_assert(invariant(f)); daemon_assert(host_port != NULL); if (f->epsv_all_set) { reply(f, 500, "After EPSV ALL, only EPSV allowed."); - } else if (!ip_equal(&f->client_addr, host_port)) { + } else if (!ip_equal((struct sockaddr *)&f->client_addr, host_port)) { reply(f, 500, "Port must be on command channel IP."); - } else if (ntohs(SINPORT(host_port)) < IPPORT_RESERVED) { +#ifdef INET6 + } else if (sockaddr_port(host_port, sizeof(struct sockaddr_storage)) + < IPPORT_RESERVED) { +#else + } else if (sockaddr_port(host_port, sizeof(struct sockaddr_in)) + < IPPORT_RESERVED) { +#endif reply(f, 500, "Port may not be less than 1024, which is reserved."); } else { /* close any outstanding PASSIVE port */ @@ -645,7 +656,11 @@ } f->data_channel = DATA_PORT; - f->data_port = *host_port; +#ifdef INET6 + memcpy(&f->data_port, host_port, sizeof(struct sockaddr_in6)); +#else + memcpy(&f->data_port, host_port, sizeof(struct sockaddr_in)); +#endif reply(f, 200, "Command okay."); } @@ -655,16 +670,20 @@ /* set IP and port for client to receive data on */ static void do_port(ftp_session_t *f, const ftp_command_t *cmd) { - const sockaddr_storage_t *host_port; +#ifdef INET6 + const struct sockaddr_storage *host_port; +#else + const struct sockaddr_in *host_port; +#endif daemon_assert(invariant(f)); daemon_assert(cmd != NULL); daemon_assert(cmd->num_arg == 1); host_port = &cmd->arg[0].host_port; - daemon_assert(SSFAM(host_port) == AF_INET); + daemon_assert(((struct sockaddr *)host_port)->sa_family == AF_INET); - set_port(f, host_port); + set_port(f, (struct sockaddr *)host_port); daemon_assert(invariant(f)); } @@ -672,7 +691,12 @@ /* set IP and port for client to receive data on, transport independent */ static void do_lprt(ftp_session_t *f, const ftp_command_t *cmd) { - const sockaddr_storage_t *host_port; +#ifdef INET6 + const struct sockaddr_storage *host_port; +#else + const struct sockaddr_in *host_port; +#endif + struct sockaddr_in6 *tmp = (struct sockaddr_in6 *)host_port; daemon_assert(invariant(f)); daemon_assert(cmd != NULL); @@ -681,16 +705,30 @@ host_port = &cmd->arg[0].host_port; #ifdef INET6 - if ((SSFAM(host_port) != AF_INET) && (SSFAM(host_port) != AF_INET6)) { + if ((((struct sockaddr *)host_port)->sa_family != AF_INET) && + (((struct sockaddr *)host_port)->sa_family != AF_INET6)) { reply(f, 521, "Only IPv4 and IPv6 supported, address families (4,6)"); } #else - if (SSFAM(host_port) != AF_INET) { + if (((struct sockaddr *)host_port)->sa_family != AF_INET) { reply(f, 521, "Only IPv4 supported, address family (4)"); } #endif - set_port(f, host_port); + /* + syslog(LOG_WARNING, "host is %d:%d:%d:%d:%d:%d:%d:%d %d", + ntohs(((struct sockaddr_in6 *)host_port)->sin6_addr.s6_addr16[0]), + ntohs(((struct sockaddr_in6 *)host_port)->sin6_addr.s6_addr16[1]), + ntohs(((struct sockaddr_in6 *)host_port)->sin6_addr.s6_addr16[2]), + ntohs(((struct sockaddr_in6 *)host_port)->sin6_addr.s6_addr16[3]), + ntohs(((struct sockaddr_in6 *)host_port)->sin6_addr.s6_addr16[4]), + ntohs(((struct sockaddr_in6 *)host_port)->sin6_addr.s6_addr16[5]), + ntohs(((struct sockaddr_in6 *)host_port)->sin6_addr.s6_addr16[6]), + ntohs(((struct sockaddr_in6 *)host_port)->sin6_addr.s6_addr16[7]), + sockaddr_port(host_port, sizeof(struct sockaddr_storage))); + */ + + set_port(f, (struct sockaddr *)host_port); daemon_assert(invariant(f)); } @@ -703,7 +741,11 @@ /* requests. */ static void do_eprt(ftp_session_t *f, const ftp_command_t *cmd) { - const sockaddr_storage_t *host_port; +#ifdef INET6 + const struct sockaddr_storage *host_port; +#else + const struct sockaddr_in *host_port; +#endif daemon_assert(invariant(f)); daemon_assert(cmd != NULL); @@ -717,15 +759,17 @@ /* support for the various pasv setting functions */ /* returns the file descriptor of the bound port, or -1 on error */ /* note: the "host_port" parameter will be modified, having its port set */ -static int set_pasv(ftp_session_t *f, sockaddr_storage_t *bind_addr) +static int set_pasv(ftp_session_t *f, struct sockaddr *bind_addr) { int socket_fd; int port; + sa_family_t family; daemon_assert(invariant(f)); daemon_assert(bind_addr != NULL); - socket_fd = socket(SSFAM(bind_addr), SOCK_STREAM, 0); + family = ((struct sockaddr *)bind_addr)->sa_family; + socket_fd = socket(family, SOCK_STREAM, 0); if (socket_fd == -1) { reply(f, 500, "Error creating server socket; %s.", strerror(errno)); return -1; @@ -733,9 +777,19 @@ for (;;) { port = get_passive_port(); - SINPORT(bind_addr) = htons(port); +#ifdef INET6 + if (((struct sockaddr *)bind_addr)->sa_family == AF_INET6) { + ((struct sockaddr_in6 *)bind_addr)->sin6_port = htons(port); + } else +#endif + ((struct sockaddr_in *)bind_addr)->sin_port = htons(port); + if (bind(socket_fd, (struct sockaddr *)bind_addr, - sizeof(struct sockaddr)) == 0) +#ifdef INET6 + sizeof(struct sockaddr_storage)) == 0) +#else + sizeof(struct sockaddr_in)) == 0) +#endif { break; } @@ -771,14 +825,23 @@ goto exit_pasv; } - socket_fd = set_pasv(f, &f->server_ipv4_addr); +#ifdef INET6 + socket_fd = set_pasv(f, (struct sockaddr *)&f->server_ipv4_addr); +#else + socket_fd = set_pasv(f, (struct sockaddr *)&f->server_addr); +#endif if (socket_fd == -1) { goto exit_pasv; } /* report port to client */ +#ifdef INET6 addr = ntohl(f->server_ipv4_addr.sin_addr.s_addr); port = ntohs(f->server_ipv4_addr.sin_port); +#else + addr = ntohl(f->server_addr.sin_addr.s_addr); + port = ntohs(f->server_addr.sin_port); +#endif reply(f, 227, "Entering Passive Mode (%d,%d,%d,%d,%d,%d).", addr >> 24, (addr >> 16) & 0xff, @@ -815,16 +878,16 @@ goto exit_lpsv; } - socket_fd = set_pasv(f, &f->server_addr); + socket_fd = set_pasv(f, (struct sockaddr *)&f->server_addr); if (socket_fd == -1) { goto exit_lpsv; } - /* report address and port to client */ + /* report address and port to server */ #ifdef INET6 - if (SSFAM(&f->server_addr) == AF_INET6) { - a = (uint8_t *)&SIN6ADDR(&f->server_addr); - p = (uint8_t *)&SIN6PORT(&f->server_addr); + if (((struct sockaddr *)&f->server_addr)->sa_family == AF_INET6) { + a = (uint8_t *)&(((struct sockaddr_in6 *)&f->server_addr)->sin6_addr); + p = (uint8_t *)&(((struct sockaddr_in6 *)&f->server_addr)->sin6_port); snprintf(addr, sizeof(addr), "(6,16,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,2,%d,%d)", a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], @@ -832,8 +895,8 @@ } else #endif { - a = (uint8_t *)&SIN4ADDR(&f->server_addr); - p = (uint8_t *)&SIN4PORT(&f->server_addr); + a = (uint8_t *)&(((struct sockaddr_in *)&f->server_addr)->sin_addr); + p = (uint8_t *)&(((struct sockaddr_in *)&f->server_addr)->sin_port); snprintf(addr, sizeof(addr), "(4,4,%d,%d,%d,%d,2,%d,%d)", a[0], a[1], a[2], a[3], p[0], p[1]); } @@ -855,7 +918,7 @@ static void do_epsv(ftp_session_t *f, const ftp_command_t *cmd) { int socket_fd; - sockaddr_storage_t *addr; + struct sockaddr *addr; daemon_assert(invariant(f)); daemon_assert(cmd != NULL); @@ -863,10 +926,10 @@ /* check our argument, if any, and use the appropriate address */ if (cmd->num_arg == 0) { - addr = &f->server_addr; + addr = (struct sockaddr *)&f->server_addr; } else { switch (cmd->arg[0].num) { - /* EPSV_ALL is a special number indicating the client sent */ + /* EPSV_ALL is a special number indicating the server sent */ /* the command "EPSV ALL" - this is not a request to assign */ /* a new passive port, but rather to deny all future port */ /* assignment requests other than EPSV */ @@ -874,17 +937,20 @@ f->epsv_all_set = 1; reply(f, 200, "EPSV ALL command successful."); goto exit_epsv; +#ifdef INET6 case 1: - addr = (sockaddr_storage_t *)&f->server_ipv4_addr; + addr = (struct sockaddr *)&f->server_ipv4_addr; break; -#ifdef INET6 case 2: - addr = &f->server_addr; + addr = (struct sockaddr *)&f->server_addr; break; default: reply(f, 522, "Only IPv4 and IPv6 supported, use (1,2)"); goto exit_epsv; #else + case 1: + addr = (struct sockaddr *)&f->server_addr; + break; default: reply(f, 522, "Only IPv4 supported, use (1)"); goto exit_epsv; @@ -900,7 +966,8 @@ /* report port to client */ reply(f, 229, "Entering Extended Passive Mode (|||%d|)", - ntohs(SINPORT(&f->server_addr))); + sockaddr_port((struct sockaddr *)&f->server_addr, + sizeof(f->server_addr))); /* close any outstanding PASSIVE port */ if (f->data_channel == DATA_PASSIVE) { @@ -1278,29 +1345,36 @@ static int open_connection(ftp_session_t *f) { int socket_fd; +#ifdef INET6 + struct sockaddr_storage addr; +#else struct sockaddr_in addr; +#endif unsigned addr_len; + sa_family_t family; daemon_assert((f->data_channel == DATA_PORT) || (f->data_channel == DATA_PASSIVE)); if (f->data_channel == DATA_PORT) { - socket_fd = socket(SSFAM(&f->data_port), SOCK_STREAM, 0); + family = ((struct sockaddr *)&f->data_port)->sa_family; + socket_fd = socket(family, SOCK_STREAM, 0); if (socket_fd == -1) { reply(f, 425, "Error creating socket; %s.", strerror(errno)); return -1; } if (connect(socket_fd, (struct sockaddr *)&f->data_port, - sizeof(sockaddr_storage_t)) != 0) + sizeof(f->data_port)) != 0) { reply(f, 425, "Error connecting; %s.", strerror(errno)); close(socket_fd); return -1; } } else { + sa_family_t a, b; daemon_assert(f->data_channel == DATA_PASSIVE); - addr_len = sizeof(struct sockaddr_in); + addr_len = sizeof(addr); socket_fd = accept(f->server_fd, (struct sockaddr *)&addr, &addr_len); if (socket_fd == -1) { reply(f, 425, "Error accepting connection; %s.", strerror(errno)); @@ -1310,15 +1384,31 @@ /* in IPv6, the client can connect to a channel using a different */ /* protocol - in that case, we'll just blindly let the connection */ /* through, otherwise verify addresses match */ - if (SAFAM(addr) == SSFAM(&f->client_addr)) { - if (memcmp(&SINADDR(&f->client_addr), &SINADDR(&addr), - sizeof(SINADDR(&addr)))) - { - reply(f, 425, - "Error accepting connection; connection from invalid IP."); - close(socket_fd); - return -1; - } + a = ((struct sockaddr *)&addr)->sa_family; + b = ((struct sockaddr *)&f->client_addr)->sa_family; + + if (a == b) { + if (a == AF_INET6) { + if (memcmp(&(((struct sockaddr_in6 *)&addr)->sin6_addr), + &(((struct sockaddr_in6 *)&f->client_addr)->sin6_addr), + sizeof(struct in6_addr))) + { + reply(f, 425, + "Error accepting connection; connection from invalid IP."); + close(socket_fd); + return -1; + } + } else { + if (memcmp(&(((struct sockaddr_in *)&addr)->sin_addr), + &(((struct sockaddr_in *)&f->client_addr)->sin_addr), + sizeof(struct in_addr))) + { + reply(f, 425, + "Error accepting connection; connection from invalid IP."); + close(socket_fd); + return -1; + } + } } #else if (memcmp(&f->client_addr.sin_addr, @@ -1811,20 +1901,69 @@ } } +#ifdef INET6 + /* compare two addresses to see if they contain the same IP address */ -static int ip_equal(const sockaddr_storage_t *a, const sockaddr_storage_t *b) +static int ip_equal(const struct sockaddr *a, const struct sockaddr *b) { + struct sockaddr *aa, *bb; + daemon_assert(a != NULL); daemon_assert(b != NULL); - daemon_assert((SSFAM(a) == AF_INET) || (SSFAM(a) == AF_INET6)); - daemon_assert((SSFAM(b) == AF_INET) || (SSFAM(b) == AF_INET6)); - - if (SSFAM(a) != SSFAM(b)) { - return 0; + daemon_assert((a->sa_family == AF_INET) || (a->sa_family == AF_INET6)); + daemon_assert((b->sa_family == AF_INET) || (b->sa_family == AF_INET6)); + + aa = (struct sockaddr *)a; + bb = (struct sockaddr *)b; + + /* we have to handle those --damned-- IPV4MAPPED addresses */ + if (aa->sa_family != bb->sa_family) { + if (a->sa_family == AF_INET6 && + IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)a)->sin6_addr)) { + aa = (struct sockaddr *)alloca(sizeof(struct sockaddr_in)); + memset(aa, 0, sizeof(struct sockaddr_in)); + ((struct sockaddr_in *)aa)->sin_addr.s_addr = + ((struct sockaddr_in6 *)a)->sin6_addr.s6_addr32[3]; + ((struct sockaddr_in *)aa)->sin_port = + ((struct sockaddr_in6 *)a)->sin6_port; + } else if (b->sa_family == AF_INET6 && + IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)b)->sin6_addr)) { + bb = (struct sockaddr *)alloca(sizeof(struct sockaddr_in)); + memset(bb, 0, sizeof(struct sockaddr_in)); + ((struct sockaddr_in *)bb)->sin_addr.s_addr = + ((struct sockaddr_in6 *)b)->sin6_addr.s6_addr32[3]; + ((struct sockaddr_in *)bb)->sin_port = + ((struct sockaddr_in6 *)b)->sin6_port; + } else { + return 0; + } } - if (memcmp(&SINADDR(a), &SINADDR(b), sizeof(SINADDR(a))) != 0) { - return 0; + + if (aa->sa_family == AF_INET6) { + if (memcmp(&((struct sockaddr_in6 *)aa)->sin6_addr, + &((struct sockaddr_in6 *)bb)->sin6_addr, + sizeof(struct sockaddr_in6)) != 0) return 0; + } else { + if (((struct sockaddr_in *)aa)->sin_addr.s_addr != + ((struct sockaddr_in *)bb)->sin_addr.s_addr) return 0; } + return 1; } +#else + +static int ip_equal(const struct sockaddr *a, const struct sockaddr *b) +{ + daemon_assert(a != NULL); + daemon_assert(b != NULL); + daemon_assert(a->sa_family == AF_INET); + daemon_assert(b->sa_family == AF_INET); + + if (((struct sockaddr_in *)aa)->sin_addr.s_addr != + ((struct sockaddr_in *)bb)->sin_addr.s_addr) return 0; + + return 1; +} + +#endif diff -Naur oftpd-0.3.7.orig/src/ftp_session.h oftpd-0.3.7/src/ftp_session.h --- oftpd-0.3.7.orig/src/ftp_session.h 2001-05-10 23:29:12.000000000 +0000 +++ oftpd-0.3.7/src/ftp_session.h 2010-01-05 21:50:11.160303781 +0000 @@ -12,7 +12,6 @@ #include #include #include -#include "af_portability.h" #include "watchdog.h" #include "error.h" @@ -54,12 +53,20 @@ int epsv_all_set; /* address of client */ - sockaddr_storage_t client_addr; +#ifdef INET6 + struct sockaddr_storage client_addr; +#else + struct sockaddr_in client_addr; +#endif char client_addr_str[ADDRPORT_STRLEN]; /* address of server (including IPv4 version) */ - sockaddr_storage_t server_addr; +#ifdef INET6 + struct sockaddr_storage server_addr; struct sockaddr_in server_ipv4_addr; +#else + struct sockaddr_in server_addr; +#endif /* telnet session to encapsulate control channel logic */ telnet_session_t *telnet_session; @@ -70,7 +77,11 @@ /* data channel information, including type, and client address or server port depending on type */ int data_channel; - sockaddr_storage_t data_port; +#ifdef INET6 + struct sockaddr_storage data_port; +#else + struct sockaddr_in data_port; +#endif int server_fd; /* watchdog to handle timeout */ @@ -78,8 +89,8 @@ } ftp_session_t; int ftp_session_init(ftp_session_t *f, - const sockaddr_storage_t *client_addr, - const sockaddr_storage_t *server_addr, + const struct sockaddr *client_addr, + const struct sockaddr *server_addr, telnet_session_t *t, const char *dir, error_t *err); diff -Naur oftpd-0.3.7.orig/src/oftpd.c oftpd-0.3.7/src/oftpd.c --- oftpd-0.3.7.orig/src/oftpd.c 2001-05-27 22:40:27.000000000 +0000 +++ oftpd-0.3.7/src/oftpd.c 2010-01-05 21:50:11.160303781 +0000 @@ -300,7 +300,7 @@ fork_ret = fork(); - if (fork_ret == -1) { + if (fork_ret < 0) { fprintf(stderr, "%s: error forking; %s\n", exe_name, strerror(errno)); exit(1); } @@ -313,7 +313,7 @@ exit(1); } fork_ret = fork(); - if (fork_ret == -1) { + if (fork_ret < 0) { fprintf(stderr, "%s: error forking; %s\n", exe_name, strerror(errno)); exit(1); }