Lines 52-63
Link Here
|
52 |
static void init_passive_port(); |
52 |
static void init_passive_port(); |
53 |
static int get_passive_port(); |
53 |
static int get_passive_port(); |
54 |
static int convert_newlines(char *dst, const char *src, int srclen); |
54 |
static int convert_newlines(char *dst, const char *src, int srclen); |
55 |
static void get_addr_str(const sockaddr_storage_t *s, char *buf, int bufsiz); |
55 |
static void get_addr_str(const struct sockaddr *s, char *buf, int bufsiz); |
56 |
static void send_readme(const ftp_session_t *f, int code); |
56 |
static void send_readme(const ftp_session_t *f, int code); |
57 |
static void netscape_hack(int fd); |
57 |
static void netscape_hack(int fd); |
58 |
static void set_port(ftp_session_t *f, const sockaddr_storage_t *host_port); |
58 |
static void set_port(ftp_session_t *f, const struct sockaddr *host_port); |
59 |
static int set_pasv(ftp_session_t *f, sockaddr_storage_t *host_port); |
59 |
static int set_pasv(ftp_session_t *f, struct sockaddr *host_port); |
60 |
static int ip_equal(const sockaddr_storage_t *a, const sockaddr_storage_t *b); |
60 |
static int ip_equal(const struct sockaddr *a, const struct sockaddr *b); |
61 |
static void get_absolute_fname(char *fname, |
61 |
static void get_absolute_fname(char *fname, |
62 |
int fname_len, |
62 |
int fname_len, |
63 |
const char *dir, |
63 |
const char *dir, |
Lines 123-130
Link Here
|
123 |
|
123 |
|
124 |
|
124 |
|
125 |
int ftp_session_init(ftp_session_t *f, |
125 |
int ftp_session_init(ftp_session_t *f, |
126 |
const sockaddr_storage_t *client_addr, |
126 |
const struct sockaddr *client_addr, |
127 |
const sockaddr_storage_t *server_addr, |
127 |
const struct sockaddr *server_addr, |
128 |
telnet_session_t *t, |
128 |
telnet_session_t *t, |
129 |
const char *dir, |
129 |
const char *dir, |
130 |
error_t *err) |
130 |
error_t *err) |
Lines 138-146
Link Here
|
138 |
daemon_assert(err != NULL); |
138 |
daemon_assert(err != NULL); |
139 |
|
139 |
|
140 |
#ifdef INET6 |
140 |
#ifdef INET6 |
141 |
/* if the control connection is on IPv6, we need to get an IPv4 address */ |
141 |
/* if the control connection is on IPv6, we need to get an IPv4 address |
142 |
/* to bind the socket to */ |
142 |
* to bind the socket to */ |
143 |
if (SSFAM(server_addr) == AF_INET6) { |
143 |
if (server_addr->sa_family == AF_INET6) { |
144 |
struct addrinfo hints; |
144 |
struct addrinfo hints; |
145 |
struct addrinfo *res; |
145 |
struct addrinfo *res; |
146 |
int errcode; |
146 |
int errcode; |
Lines 149-156
Link Here
|
149 |
memset(&hints, 0, sizeof(struct addrinfo)); |
149 |
memset(&hints, 0, sizeof(struct addrinfo)); |
150 |
hints.ai_family = AF_INET; |
150 |
hints.ai_family = AF_INET; |
151 |
hints.ai_flags = AI_PASSIVE; |
151 |
hints.ai_flags = AI_PASSIVE; |
152 |
if (getaddrinfo(NULL, "ftp", &hints, &res) != 0) { |
152 |
hints.ai_socktype = SOCK_STREAM; |
153 |
error_init(err, 0, "unable to determing IPv4 address; %s", |
153 |
|
|
|
154 |
if ((errcode = getaddrinfo(NULL, "21", &hints, &res)) != 0) { |
155 |
error_init(err, 0, "unable to determine IPv4 address; %s", |
154 |
gai_strerror(errcode)); |
156 |
gai_strerror(errcode)); |
155 |
return 0; |
157 |
return 0; |
156 |
} |
158 |
} |
Lines 158-174
Link Here
|
158 |
/* let's sanity check */ |
160 |
/* let's sanity check */ |
159 |
daemon_assert(res != NULL); |
161 |
daemon_assert(res != NULL); |
160 |
daemon_assert(sizeof(f->server_ipv4_addr) >= res->ai_addrlen); |
162 |
daemon_assert(sizeof(f->server_ipv4_addr) >= res->ai_addrlen); |
161 |
daemon_assert(SSFAM(host_port) == AF_INET); |
163 |
daemon_assert(res->ai_addr->sa_family == AF_INET); |
162 |
|
164 |
|
163 |
/* copy the result and free memory as necessary */ |
165 |
/* copy the result and free memory as necessary */ |
164 |
memcpy(&f->server_ipv4_addr, res->ai_addr, res->ai_addrlen); |
166 |
memcpy(&f->server_ipv4_addr, res->ai_addr, res->ai_addrlen); |
165 |
freeaddrinfo(res); |
167 |
freeaddrinfo(res); |
166 |
} else { |
168 |
} else { |
167 |
daemon_assert(SSFAM(host_port) == AF_INET); |
169 |
f->server_ipv4_addr = *((struct sockaddr_in *)server_addr); |
168 |
f->server_ipv4_addr = *server_addr; |
|
|
169 |
} |
170 |
} |
170 |
#else |
|
|
171 |
f->server_ipv4_addr = *server_addr; |
172 |
#endif |
171 |
#endif |
173 |
|
172 |
|
174 |
f->session_active = 1; |
173 |
f->session_active = 1; |
Lines 182-198
Link Here
|
182 |
|
181 |
|
183 |
f->epsv_all_set = 0; |
182 |
f->epsv_all_set = 0; |
184 |
|
183 |
|
185 |
f->client_addr = *client_addr; |
184 |
#ifdef INET6 |
|
|
185 |
memcpy(&f->client_addr, client_addr, sizeof(struct sockaddr_in6)); |
186 |
memcpy(&f->server_addr, server_addr, sizeof(struct sockaddr_in6)); |
187 |
memcpy(&f->data_port, client_addr, sizeof(struct sockaddr_in6)); |
188 |
#else |
189 |
memcpy(&f->client_addr, client_addr, sizeof(struct sockaddr_in)); |
190 |
memcpy(&f->server_addr, server_addr, sizeof(struct sockaddr_in)); |
191 |
memcpy(&f->data_port, client_addr, sizeof(struct sockaddr_in)); |
192 |
#endif |
186 |
get_addr_str(client_addr, f->client_addr_str, sizeof(f->client_addr_str)); |
193 |
get_addr_str(client_addr, f->client_addr_str, sizeof(f->client_addr_str)); |
187 |
|
194 |
|
188 |
f->server_addr = *server_addr; |
|
|
189 |
|
190 |
f->telnet_session = t; |
195 |
f->telnet_session = t; |
191 |
daemon_assert(strlen(dir) < sizeof(f->dir)); |
196 |
daemon_assert(strlen(dir) < sizeof(f->dir)); |
192 |
strcpy(f->dir, dir); |
197 |
strcpy(f->dir, dir); |
193 |
|
198 |
|
194 |
f->data_channel = DATA_PORT; |
199 |
f->data_channel = DATA_PORT; |
195 |
f->data_port = *client_addr; |
|
|
196 |
f->server_fd = -1; |
200 |
f->server_fd = -1; |
197 |
|
201 |
|
198 |
daemon_assert(invariant(f)); |
202 |
daemon_assert(invariant(f)); |
Lines 326-332
Link Here
|
326 |
/* If the client specifies a port, verify that it is from the */ |
330 |
/* If the client specifies a port, verify that it is from the */ |
327 |
/* host the client connected from. This prevents a client from */ |
331 |
/* host the client connected from. This prevents a client from */ |
328 |
/* using the server to open connections to arbritrary hosts. */ |
332 |
/* using the server to open connections to arbritrary hosts. */ |
329 |
if (!ip_equal(&f->client_addr, &f->data_port)) { |
333 |
if (!ip_equal((struct sockaddr *)&f->client_addr, |
|
|
334 |
(struct sockaddr *)&f->data_port)) { |
330 |
return 0; |
335 |
return 0; |
331 |
} |
336 |
} |
332 |
if (f->server_fd != -1) { |
337 |
if (f->server_fd != -1) { |
Lines 412-418
Link Here
|
412 |
} |
417 |
} |
413 |
|
418 |
|
414 |
#ifdef INET6 |
419 |
#ifdef INET6 |
415 |
static void get_addr_str(const sockaddr_storage_t *s, char *buf, int bufsiz) |
420 |
static void get_addr_str(const struct sockaddr *s, char *buf, int bufsiz) |
416 |
{ |
421 |
{ |
417 |
int port; |
422 |
int port; |
418 |
int error; |
423 |
int error; |
Lines 426-442
Link Here
|
426 |
* number (which is 5 chars max), plus the '\0' character. */ |
431 |
* number (which is 5 chars max), plus the '\0' character. */ |
427 |
daemon_assert(bufsiz >= (INET_ADDRSTRLEN + 12)); |
432 |
daemon_assert(bufsiz >= (INET_ADDRSTRLEN + 12)); |
428 |
|
433 |
|
429 |
error = getnameinfo(client_addr, sizeof(sockaddr_storage_t), buf, |
434 |
error = getnameinfo(s, sizeof(struct sockaddr_storage), buf, |
430 |
bufsiz, NULL, 0, NI_NUMERICHOST); |
435 |
bufsiz, NULL, 0, NI_NUMERICHOST); |
431 |
/* getnameinfo() should never fail when called with NI_NUMERICHOST */ |
436 |
/* getnameinfo() should never fail when called with NI_NUMERICHOST */ |
432 |
daemon_assert(error == 0); |
437 |
daemon_assert(error == 0); |
433 |
|
438 |
|
434 |
len = strlen(buf); |
439 |
len = strlen(buf); |
435 |
daemon_assert(bufsiz >= len+12); |
440 |
daemon_assert(bufsiz >= len+12); |
436 |
snprintf(buf+len, bufsiz-len, " port %d", ntohs(SINPORT(&f->client_addr))); |
441 |
snprintf(buf+len, bufsiz-len, " port %d", sockaddr_port((struct sockaddr *)s, sizeof(s))); |
437 |
} |
442 |
} |
438 |
#else |
443 |
#else |
439 |
static void get_addr_str(const sockaddr_storage_t *s, char *buf, int bufsiz) |
444 |
static void get_addr_str(const struct sockaddr *s, char *buf, int bufsiz) |
440 |
{ |
445 |
{ |
441 |
unsigned int addr; |
446 |
unsigned int addr; |
442 |
int port; |
447 |
int port; |
Lines 449-456
Link Here
|
449 |
* number (which is 5 chars max), plus the '\0' character. */ |
454 |
* number (which is 5 chars max), plus the '\0' character. */ |
450 |
daemon_assert(bufsiz >= (INET_ADDRSTRLEN + 12)); |
455 |
daemon_assert(bufsiz >= (INET_ADDRSTRLEN + 12)); |
451 |
|
456 |
|
452 |
addr = ntohl(s->sin_addr.s_addr); |
457 |
addr = ntohl(((struct sockaddr_in *)s)->sin_addr.s_addr); |
453 |
port = ntohs(s->sin_port); |
458 |
port = ntohs(((struct sockaddr_in *)s)->sin_port); |
454 |
snprintf(buf, bufsiz, "%d.%d.%d.%d port %d", |
459 |
snprintf(buf, bufsiz, "%d.%d.%d.%d port %d", |
455 |
(addr >> 24) & 0xff, |
460 |
(addr >> 24) & 0xff, |
456 |
(addr >> 16) & 0xff, |
461 |
(addr >> 16) & 0xff, |
Lines 626-641
Link Here
|
626 |
} |
631 |
} |
627 |
|
632 |
|
628 |
/* support for the various port setting functions */ |
633 |
/* support for the various port setting functions */ |
629 |
static void set_port(ftp_session_t *f, const sockaddr_storage_t *host_port) |
634 |
static void set_port(ftp_session_t *f, const struct sockaddr *host_port) |
630 |
{ |
635 |
{ |
631 |
daemon_assert(invariant(f)); |
636 |
daemon_assert(invariant(f)); |
632 |
daemon_assert(host_port != NULL); |
637 |
daemon_assert(host_port != NULL); |
633 |
|
638 |
|
634 |
if (f->epsv_all_set) { |
639 |
if (f->epsv_all_set) { |
635 |
reply(f, 500, "After EPSV ALL, only EPSV allowed."); |
640 |
reply(f, 500, "After EPSV ALL, only EPSV allowed."); |
636 |
} else if (!ip_equal(&f->client_addr, host_port)) { |
641 |
} else if (!ip_equal((struct sockaddr *)&f->client_addr, host_port)) { |
637 |
reply(f, 500, "Port must be on command channel IP."); |
642 |
reply(f, 500, "Port must be on command channel IP."); |
638 |
} else if (ntohs(SINPORT(host_port)) < IPPORT_RESERVED) { |
643 |
#ifdef INET6 |
|
|
644 |
} else if (sockaddr_port(host_port, sizeof(struct sockaddr_storage)) |
645 |
< IPPORT_RESERVED) { |
646 |
#else |
647 |
} else if (sockaddr_port(host_port, sizeof(struct sockaddr_in)) |
648 |
< IPPORT_RESERVED) { |
649 |
#endif |
639 |
reply(f, 500, "Port may not be less than 1024, which is reserved."); |
650 |
reply(f, 500, "Port may not be less than 1024, which is reserved."); |
640 |
} else { |
651 |
} else { |
641 |
/* close any outstanding PASSIVE port */ |
652 |
/* close any outstanding PASSIVE port */ |
Lines 645-651
Link Here
|
645 |
} |
656 |
} |
646 |
|
657 |
|
647 |
f->data_channel = DATA_PORT; |
658 |
f->data_channel = DATA_PORT; |
648 |
f->data_port = *host_port; |
659 |
#ifdef INET6 |
|
|
660 |
memcpy(&f->data_port, host_port, sizeof(struct sockaddr_in6)); |
661 |
#else |
662 |
memcpy(&f->data_port, host_port, sizeof(struct sockaddr_in)); |
663 |
#endif |
649 |
reply(f, 200, "Command okay."); |
664 |
reply(f, 200, "Command okay."); |
650 |
} |
665 |
} |
651 |
|
666 |
|
Lines 655-670
Link Here
|
655 |
/* set IP and port for client to receive data on */ |
670 |
/* set IP and port for client to receive data on */ |
656 |
static void do_port(ftp_session_t *f, const ftp_command_t *cmd) |
671 |
static void do_port(ftp_session_t *f, const ftp_command_t *cmd) |
657 |
{ |
672 |
{ |
658 |
const sockaddr_storage_t *host_port; |
673 |
#ifdef INET6 |
|
|
674 |
const struct sockaddr_storage *host_port; |
675 |
#else |
676 |
const struct sockaddr_in *host_port; |
677 |
#endif |
659 |
|
678 |
|
660 |
daemon_assert(invariant(f)); |
679 |
daemon_assert(invariant(f)); |
661 |
daemon_assert(cmd != NULL); |
680 |
daemon_assert(cmd != NULL); |
662 |
daemon_assert(cmd->num_arg == 1); |
681 |
daemon_assert(cmd->num_arg == 1); |
663 |
|
682 |
|
664 |
host_port = &cmd->arg[0].host_port; |
683 |
host_port = &cmd->arg[0].host_port; |
665 |
daemon_assert(SSFAM(host_port) == AF_INET); |
684 |
daemon_assert(((struct sockaddr *)host_port)->sa_family == AF_INET); |
666 |
|
685 |
|
667 |
set_port(f, host_port); |
686 |
set_port(f, (struct sockaddr *)host_port); |
668 |
|
687 |
|
669 |
daemon_assert(invariant(f)); |
688 |
daemon_assert(invariant(f)); |
670 |
} |
689 |
} |
Lines 672-678
Link Here
|
672 |
/* set IP and port for client to receive data on, transport independent */ |
691 |
/* set IP and port for client to receive data on, transport independent */ |
673 |
static void do_lprt(ftp_session_t *f, const ftp_command_t *cmd) |
692 |
static void do_lprt(ftp_session_t *f, const ftp_command_t *cmd) |
674 |
{ |
693 |
{ |
675 |
const sockaddr_storage_t *host_port; |
694 |
#ifdef INET6 |
|
|
695 |
const struct sockaddr_storage *host_port; |
696 |
#else |
697 |
const struct sockaddr_in *host_port; |
698 |
#endif |
699 |
struct sockaddr_in6 *tmp = (struct sockaddr_in6 *)host_port; |
676 |
|
700 |
|
677 |
daemon_assert(invariant(f)); |
701 |
daemon_assert(invariant(f)); |
678 |
daemon_assert(cmd != NULL); |
702 |
daemon_assert(cmd != NULL); |
Lines 681-696
Link Here
|
681 |
host_port = &cmd->arg[0].host_port; |
705 |
host_port = &cmd->arg[0].host_port; |
682 |
|
706 |
|
683 |
#ifdef INET6 |
707 |
#ifdef INET6 |
684 |
if ((SSFAM(host_port) != AF_INET) && (SSFAM(host_port) != AF_INET6)) { |
708 |
if ((((struct sockaddr *)host_port)->sa_family != AF_INET) && |
|
|
709 |
(((struct sockaddr *)host_port)->sa_family != AF_INET6)) { |
685 |
reply(f, 521, "Only IPv4 and IPv6 supported, address families (4,6)"); |
710 |
reply(f, 521, "Only IPv4 and IPv6 supported, address families (4,6)"); |
686 |
} |
711 |
} |
687 |
#else |
712 |
#else |
688 |
if (SSFAM(host_port) != AF_INET) { |
713 |
if (((struct sockaddr *)host_port)->sa_family != AF_INET) { |
689 |
reply(f, 521, "Only IPv4 supported, address family (4)"); |
714 |
reply(f, 521, "Only IPv4 supported, address family (4)"); |
690 |
} |
715 |
} |
691 |
#endif |
716 |
#endif |
692 |
|
717 |
|
693 |
set_port(f, host_port); |
718 |
/* |
|
|
719 |
syslog(LOG_WARNING, "host is %d:%d:%d:%d:%d:%d:%d:%d %d", |
720 |
ntohs(((struct sockaddr_in6 *)host_port)->sin6_addr.s6_addr16[0]), |
721 |
ntohs(((struct sockaddr_in6 *)host_port)->sin6_addr.s6_addr16[1]), |
722 |
ntohs(((struct sockaddr_in6 *)host_port)->sin6_addr.s6_addr16[2]), |
723 |
ntohs(((struct sockaddr_in6 *)host_port)->sin6_addr.s6_addr16[3]), |
724 |
ntohs(((struct sockaddr_in6 *)host_port)->sin6_addr.s6_addr16[4]), |
725 |
ntohs(((struct sockaddr_in6 *)host_port)->sin6_addr.s6_addr16[5]), |
726 |
ntohs(((struct sockaddr_in6 *)host_port)->sin6_addr.s6_addr16[6]), |
727 |
ntohs(((struct sockaddr_in6 *)host_port)->sin6_addr.s6_addr16[7]), |
728 |
sockaddr_port(host_port, sizeof(struct sockaddr_storage))); |
729 |
*/ |
730 |
|
731 |
set_port(f, (struct sockaddr *)host_port); |
694 |
|
732 |
|
695 |
daemon_assert(invariant(f)); |
733 |
daemon_assert(invariant(f)); |
696 |
} |
734 |
} |
Lines 703-709
Link Here
|
703 |
/* requests. */ |
741 |
/* requests. */ |
704 |
static void do_eprt(ftp_session_t *f, const ftp_command_t *cmd) |
742 |
static void do_eprt(ftp_session_t *f, const ftp_command_t *cmd) |
705 |
{ |
743 |
{ |
706 |
const sockaddr_storage_t *host_port; |
744 |
#ifdef INET6 |
|
|
745 |
const struct sockaddr_storage *host_port; |
746 |
#else |
747 |
const struct sockaddr_in *host_port; |
748 |
#endif |
707 |
|
749 |
|
708 |
daemon_assert(invariant(f)); |
750 |
daemon_assert(invariant(f)); |
709 |
daemon_assert(cmd != NULL); |
751 |
daemon_assert(cmd != NULL); |
Lines 717-731
Link Here
|
717 |
/* support for the various pasv setting functions */ |
759 |
/* support for the various pasv setting functions */ |
718 |
/* returns the file descriptor of the bound port, or -1 on error */ |
760 |
/* returns the file descriptor of the bound port, or -1 on error */ |
719 |
/* note: the "host_port" parameter will be modified, having its port set */ |
761 |
/* note: the "host_port" parameter will be modified, having its port set */ |
720 |
static int set_pasv(ftp_session_t *f, sockaddr_storage_t *bind_addr) |
762 |
static int set_pasv(ftp_session_t *f, struct sockaddr *bind_addr) |
721 |
{ |
763 |
{ |
722 |
int socket_fd; |
764 |
int socket_fd; |
723 |
int port; |
765 |
int port; |
|
|
766 |
sa_family_t family; |
724 |
|
767 |
|
725 |
daemon_assert(invariant(f)); |
768 |
daemon_assert(invariant(f)); |
726 |
daemon_assert(bind_addr != NULL); |
769 |
daemon_assert(bind_addr != NULL); |
727 |
|
770 |
|
728 |
socket_fd = socket(SSFAM(bind_addr), SOCK_STREAM, 0); |
771 |
family = ((struct sockaddr *)bind_addr)->sa_family; |
|
|
772 |
socket_fd = socket(family, SOCK_STREAM, 0); |
729 |
if (socket_fd == -1) { |
773 |
if (socket_fd == -1) { |
730 |
reply(f, 500, "Error creating server socket; %s.", strerror(errno)); |
774 |
reply(f, 500, "Error creating server socket; %s.", strerror(errno)); |
731 |
return -1; |
775 |
return -1; |
Lines 733-741
Link Here
|
733 |
|
777 |
|
734 |
for (;;) { |
778 |
for (;;) { |
735 |
port = get_passive_port(); |
779 |
port = get_passive_port(); |
736 |
SINPORT(bind_addr) = htons(port); |
780 |
#ifdef INET6 |
|
|
781 |
if (((struct sockaddr *)bind_addr)->sa_family == AF_INET6) { |
782 |
((struct sockaddr_in6 *)bind_addr)->sin6_port = htons(port); |
783 |
} else |
784 |
#endif |
785 |
((struct sockaddr_in *)bind_addr)->sin_port = htons(port); |
786 |
|
737 |
if (bind(socket_fd, (struct sockaddr *)bind_addr, |
787 |
if (bind(socket_fd, (struct sockaddr *)bind_addr, |
738 |
sizeof(struct sockaddr)) == 0) |
788 |
#ifdef INET6 |
|
|
789 |
sizeof(struct sockaddr_storage)) == 0) |
790 |
#else |
791 |
sizeof(struct sockaddr_in)) == 0) |
792 |
#endif |
739 |
{ |
793 |
{ |
740 |
break; |
794 |
break; |
741 |
} |
795 |
} |
Lines 771-784
Link Here
|
771 |
goto exit_pasv; |
825 |
goto exit_pasv; |
772 |
} |
826 |
} |
773 |
|
827 |
|
774 |
socket_fd = set_pasv(f, &f->server_ipv4_addr); |
828 |
#ifdef INET6 |
|
|
829 |
socket_fd = set_pasv(f, (struct sockaddr *)&f->server_ipv4_addr); |
830 |
#else |
831 |
socket_fd = set_pasv(f, (struct sockaddr *)&f->server_addr); |
832 |
#endif |
775 |
if (socket_fd == -1) { |
833 |
if (socket_fd == -1) { |
776 |
goto exit_pasv; |
834 |
goto exit_pasv; |
777 |
} |
835 |
} |
778 |
|
836 |
|
779 |
/* report port to client */ |
837 |
/* report port to client */ |
|
|
838 |
#ifdef INET6 |
780 |
addr = ntohl(f->server_ipv4_addr.sin_addr.s_addr); |
839 |
addr = ntohl(f->server_ipv4_addr.sin_addr.s_addr); |
781 |
port = ntohs(f->server_ipv4_addr.sin_port); |
840 |
port = ntohs(f->server_ipv4_addr.sin_port); |
|
|
841 |
#else |
842 |
addr = ntohl(f->server_addr.sin_addr.s_addr); |
843 |
port = ntohs(f->server_addr.sin_port); |
844 |
#endif |
782 |
reply(f, 227, "Entering Passive Mode (%d,%d,%d,%d,%d,%d).", |
845 |
reply(f, 227, "Entering Passive Mode (%d,%d,%d,%d,%d,%d).", |
783 |
addr >> 24, |
846 |
addr >> 24, |
784 |
(addr >> 16) & 0xff, |
847 |
(addr >> 16) & 0xff, |
Lines 815-830
Link Here
|
815 |
goto exit_lpsv; |
878 |
goto exit_lpsv; |
816 |
} |
879 |
} |
817 |
|
880 |
|
818 |
socket_fd = set_pasv(f, &f->server_addr); |
881 |
socket_fd = set_pasv(f, (struct sockaddr *)&f->server_addr); |
819 |
if (socket_fd == -1) { |
882 |
if (socket_fd == -1) { |
820 |
goto exit_lpsv; |
883 |
goto exit_lpsv; |
821 |
} |
884 |
} |
822 |
|
885 |
|
823 |
/* report address and port to client */ |
886 |
/* report address and port to server */ |
824 |
#ifdef INET6 |
887 |
#ifdef INET6 |
825 |
if (SSFAM(&f->server_addr) == AF_INET6) { |
888 |
if (((struct sockaddr *)&f->server_addr)->sa_family == AF_INET6) { |
826 |
a = (uint8_t *)&SIN6ADDR(&f->server_addr); |
889 |
a = (uint8_t *)&(((struct sockaddr_in6 *)&f->server_addr)->sin6_addr); |
827 |
p = (uint8_t *)&SIN6PORT(&f->server_addr); |
890 |
p = (uint8_t *)&(((struct sockaddr_in6 *)&f->server_addr)->sin6_port); |
828 |
snprintf(addr, sizeof(addr), |
891 |
snprintf(addr, sizeof(addr), |
829 |
"(6,16,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,2,%d,%d)", |
892 |
"(6,16,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,2,%d,%d)", |
830 |
a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], |
893 |
a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], |
Lines 832-839
Link Here
|
832 |
} else |
895 |
} else |
833 |
#endif |
896 |
#endif |
834 |
{ |
897 |
{ |
835 |
a = (uint8_t *)&SIN4ADDR(&f->server_addr); |
898 |
a = (uint8_t *)&(((struct sockaddr_in *)&f->server_addr)->sin_addr); |
836 |
p = (uint8_t *)&SIN4PORT(&f->server_addr); |
899 |
p = (uint8_t *)&(((struct sockaddr_in *)&f->server_addr)->sin_port); |
837 |
snprintf(addr, sizeof(addr), "(4,4,%d,%d,%d,%d,2,%d,%d)", |
900 |
snprintf(addr, sizeof(addr), "(4,4,%d,%d,%d,%d,2,%d,%d)", |
838 |
a[0], a[1], a[2], a[3], p[0], p[1]); |
901 |
a[0], a[1], a[2], a[3], p[0], p[1]); |
839 |
} |
902 |
} |
Lines 855-861
Link Here
|
855 |
static void do_epsv(ftp_session_t *f, const ftp_command_t *cmd) |
918 |
static void do_epsv(ftp_session_t *f, const ftp_command_t *cmd) |
856 |
{ |
919 |
{ |
857 |
int socket_fd; |
920 |
int socket_fd; |
858 |
sockaddr_storage_t *addr; |
921 |
struct sockaddr *addr; |
859 |
|
922 |
|
860 |
daemon_assert(invariant(f)); |
923 |
daemon_assert(invariant(f)); |
861 |
daemon_assert(cmd != NULL); |
924 |
daemon_assert(cmd != NULL); |
Lines 863-872
Link Here
|
863 |
|
926 |
|
864 |
/* check our argument, if any, and use the appropriate address */ |
927 |
/* check our argument, if any, and use the appropriate address */ |
865 |
if (cmd->num_arg == 0) { |
928 |
if (cmd->num_arg == 0) { |
866 |
addr = &f->server_addr; |
929 |
addr = (struct sockaddr *)&f->server_addr; |
867 |
} else { |
930 |
} else { |
868 |
switch (cmd->arg[0].num) { |
931 |
switch (cmd->arg[0].num) { |
869 |
/* EPSV_ALL is a special number indicating the client sent */ |
932 |
/* EPSV_ALL is a special number indicating the server sent */ |
870 |
/* the command "EPSV ALL" - this is not a request to assign */ |
933 |
/* the command "EPSV ALL" - this is not a request to assign */ |
871 |
/* a new passive port, but rather to deny all future port */ |
934 |
/* a new passive port, but rather to deny all future port */ |
872 |
/* assignment requests other than EPSV */ |
935 |
/* assignment requests other than EPSV */ |
Lines 874-890
Link Here
|
874 |
f->epsv_all_set = 1; |
937 |
f->epsv_all_set = 1; |
875 |
reply(f, 200, "EPSV ALL command successful."); |
938 |
reply(f, 200, "EPSV ALL command successful."); |
876 |
goto exit_epsv; |
939 |
goto exit_epsv; |
|
|
940 |
#ifdef INET6 |
877 |
case 1: |
941 |
case 1: |
878 |
addr = (sockaddr_storage_t *)&f->server_ipv4_addr; |
942 |
addr = (struct sockaddr *)&f->server_ipv4_addr; |
879 |
break; |
943 |
break; |
880 |
#ifdef INET6 |
|
|
881 |
case 2: |
944 |
case 2: |
882 |
addr = &f->server_addr; |
945 |
addr = (struct sockaddr *)&f->server_addr; |
883 |
break; |
946 |
break; |
884 |
default: |
947 |
default: |
885 |
reply(f, 522, "Only IPv4 and IPv6 supported, use (1,2)"); |
948 |
reply(f, 522, "Only IPv4 and IPv6 supported, use (1,2)"); |
886 |
goto exit_epsv; |
949 |
goto exit_epsv; |
887 |
#else |
950 |
#else |
|
|
951 |
case 1: |
952 |
addr = (struct sockaddr *)&f->server_addr; |
953 |
break; |
888 |
default: |
954 |
default: |
889 |
reply(f, 522, "Only IPv4 supported, use (1)"); |
955 |
reply(f, 522, "Only IPv4 supported, use (1)"); |
890 |
goto exit_epsv; |
956 |
goto exit_epsv; |
Lines 900-906
Link Here
|
900 |
|
966 |
|
901 |
/* report port to client */ |
967 |
/* report port to client */ |
902 |
reply(f, 229, "Entering Extended Passive Mode (|||%d|)", |
968 |
reply(f, 229, "Entering Extended Passive Mode (|||%d|)", |
903 |
ntohs(SINPORT(&f->server_addr))); |
969 |
sockaddr_port((struct sockaddr *)&f->server_addr, |
|
|
970 |
sizeof(f->server_addr))); |
904 |
|
971 |
|
905 |
/* close any outstanding PASSIVE port */ |
972 |
/* close any outstanding PASSIVE port */ |
906 |
if (f->data_channel == DATA_PASSIVE) { |
973 |
if (f->data_channel == DATA_PASSIVE) { |
Lines 1278-1306
Link Here
|
1278 |
static int open_connection(ftp_session_t *f) |
1345 |
static int open_connection(ftp_session_t *f) |
1279 |
{ |
1346 |
{ |
1280 |
int socket_fd; |
1347 |
int socket_fd; |
|
|
1348 |
#ifdef INET6 |
1349 |
struct sockaddr_storage addr; |
1350 |
#else |
1281 |
struct sockaddr_in addr; |
1351 |
struct sockaddr_in addr; |
|
|
1352 |
#endif |
1282 |
unsigned addr_len; |
1353 |
unsigned addr_len; |
|
|
1354 |
sa_family_t family; |
1283 |
|
1355 |
|
1284 |
daemon_assert((f->data_channel == DATA_PORT) || |
1356 |
daemon_assert((f->data_channel == DATA_PORT) || |
1285 |
(f->data_channel == DATA_PASSIVE)); |
1357 |
(f->data_channel == DATA_PASSIVE)); |
1286 |
|
1358 |
|
1287 |
if (f->data_channel == DATA_PORT) { |
1359 |
if (f->data_channel == DATA_PORT) { |
1288 |
socket_fd = socket(SSFAM(&f->data_port), SOCK_STREAM, 0); |
1360 |
family = ((struct sockaddr *)&f->data_port)->sa_family; |
|
|
1361 |
socket_fd = socket(family, SOCK_STREAM, 0); |
1289 |
if (socket_fd == -1) { |
1362 |
if (socket_fd == -1) { |
1290 |
reply(f, 425, "Error creating socket; %s.", strerror(errno)); |
1363 |
reply(f, 425, "Error creating socket; %s.", strerror(errno)); |
1291 |
return -1; |
1364 |
return -1; |
1292 |
} |
1365 |
} |
1293 |
if (connect(socket_fd, (struct sockaddr *)&f->data_port, |
1366 |
if (connect(socket_fd, (struct sockaddr *)&f->data_port, |
1294 |
sizeof(sockaddr_storage_t)) != 0) |
1367 |
sizeof(f->data_port)) != 0) |
1295 |
{ |
1368 |
{ |
1296 |
reply(f, 425, "Error connecting; %s.", strerror(errno)); |
1369 |
reply(f, 425, "Error connecting; %s.", strerror(errno)); |
1297 |
close(socket_fd); |
1370 |
close(socket_fd); |
1298 |
return -1; |
1371 |
return -1; |
1299 |
} |
1372 |
} |
1300 |
} else { |
1373 |
} else { |
|
|
1374 |
sa_family_t a, b; |
1301 |
daemon_assert(f->data_channel == DATA_PASSIVE); |
1375 |
daemon_assert(f->data_channel == DATA_PASSIVE); |
1302 |
|
1376 |
|
1303 |
addr_len = sizeof(struct sockaddr_in); |
1377 |
addr_len = sizeof(addr); |
1304 |
socket_fd = accept(f->server_fd, (struct sockaddr *)&addr, &addr_len); |
1378 |
socket_fd = accept(f->server_fd, (struct sockaddr *)&addr, &addr_len); |
1305 |
if (socket_fd == -1) { |
1379 |
if (socket_fd == -1) { |
1306 |
reply(f, 425, "Error accepting connection; %s.", strerror(errno)); |
1380 |
reply(f, 425, "Error accepting connection; %s.", strerror(errno)); |
Lines 1310-1324
Link Here
|
1310 |
/* in IPv6, the client can connect to a channel using a different */ |
1384 |
/* in IPv6, the client can connect to a channel using a different */ |
1311 |
/* protocol - in that case, we'll just blindly let the connection */ |
1385 |
/* protocol - in that case, we'll just blindly let the connection */ |
1312 |
/* through, otherwise verify addresses match */ |
1386 |
/* through, otherwise verify addresses match */ |
1313 |
if (SAFAM(addr) == SSFAM(&f->client_addr)) { |
1387 |
a = ((struct sockaddr *)&addr)->sa_family; |
1314 |
if (memcmp(&SINADDR(&f->client_addr), &SINADDR(&addr), |
1388 |
b = ((struct sockaddr *)&f->client_addr)->sa_family; |
1315 |
sizeof(SINADDR(&addr)))) |
1389 |
|
1316 |
{ |
1390 |
if (a == b) { |
1317 |
reply(f, 425, |
1391 |
if (a == AF_INET6) { |
1318 |
"Error accepting connection; connection from invalid IP."); |
1392 |
if (memcmp(&(((struct sockaddr_in6 *)&addr)->sin6_addr), |
1319 |
close(socket_fd); |
1393 |
&(((struct sockaddr_in6 *)&f->client_addr)->sin6_addr), |
1320 |
return -1; |
1394 |
sizeof(struct in6_addr))) |
1321 |
} |
1395 |
{ |
|
|
1396 |
reply(f, 425, |
1397 |
"Error accepting connection; connection from invalid IP."); |
1398 |
close(socket_fd); |
1399 |
return -1; |
1400 |
} |
1401 |
} else { |
1402 |
if (memcmp(&(((struct sockaddr_in *)&addr)->sin_addr), |
1403 |
&(((struct sockaddr_in *)&f->client_addr)->sin_addr), |
1404 |
sizeof(struct in_addr))) |
1405 |
{ |
1406 |
reply(f, 425, |
1407 |
"Error accepting connection; connection from invalid IP."); |
1408 |
close(socket_fd); |
1409 |
return -1; |
1410 |
} |
1411 |
} |
1322 |
} |
1412 |
} |
1323 |
#else |
1413 |
#else |
1324 |
if (memcmp(&f->client_addr.sin_addr, |
1414 |
if (memcmp(&f->client_addr.sin_addr, |
Lines 1811-1830
Link Here
|
1811 |
} |
1901 |
} |
1812 |
} |
1902 |
} |
1813 |
|
1903 |
|
|
|
1904 |
#ifdef INET6 |
1905 |
|
1814 |
/* compare two addresses to see if they contain the same IP address */ |
1906 |
/* compare two addresses to see if they contain the same IP address */ |
1815 |
static int ip_equal(const sockaddr_storage_t *a, const sockaddr_storage_t *b) |
1907 |
static int ip_equal(const struct sockaddr *a, const struct sockaddr *b) |
1816 |
{ |
1908 |
{ |
|
|
1909 |
struct sockaddr *aa, *bb; |
1910 |
|
1817 |
daemon_assert(a != NULL); |
1911 |
daemon_assert(a != NULL); |
1818 |
daemon_assert(b != NULL); |
1912 |
daemon_assert(b != NULL); |
1819 |
daemon_assert((SSFAM(a) == AF_INET) || (SSFAM(a) == AF_INET6)); |
1913 |
daemon_assert((a->sa_family == AF_INET) || (a->sa_family == AF_INET6)); |
1820 |
daemon_assert((SSFAM(b) == AF_INET) || (SSFAM(b) == AF_INET6)); |
1914 |
daemon_assert((b->sa_family == AF_INET) || (b->sa_family == AF_INET6)); |
1821 |
|
1915 |
|
1822 |
if (SSFAM(a) != SSFAM(b)) { |
1916 |
aa = (struct sockaddr *)a; |
1823 |
return 0; |
1917 |
bb = (struct sockaddr *)b; |
|
|
1918 |
|
1919 |
/* we have to handle those --damned-- IPV4MAPPED addresses */ |
1920 |
if (aa->sa_family != bb->sa_family) { |
1921 |
if (a->sa_family == AF_INET6 && |
1922 |
IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)a)->sin6_addr)) { |
1923 |
aa = (struct sockaddr *)alloca(sizeof(struct sockaddr_in)); |
1924 |
memset(aa, 0, sizeof(struct sockaddr_in)); |
1925 |
((struct sockaddr_in *)aa)->sin_addr.s_addr = |
1926 |
((struct sockaddr_in6 *)a)->sin6_addr.s6_addr32[3]; |
1927 |
((struct sockaddr_in *)aa)->sin_port = |
1928 |
((struct sockaddr_in6 *)a)->sin6_port; |
1929 |
} else if (b->sa_family == AF_INET6 && |
1930 |
IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)b)->sin6_addr)) { |
1931 |
bb = (struct sockaddr *)alloca(sizeof(struct sockaddr_in)); |
1932 |
memset(bb, 0, sizeof(struct sockaddr_in)); |
1933 |
((struct sockaddr_in *)bb)->sin_addr.s_addr = |
1934 |
((struct sockaddr_in6 *)b)->sin6_addr.s6_addr32[3]; |
1935 |
((struct sockaddr_in *)bb)->sin_port = |
1936 |
((struct sockaddr_in6 *)b)->sin6_port; |
1937 |
} else { |
1938 |
return 0; |
1939 |
} |
1824 |
} |
1940 |
} |
1825 |
if (memcmp(&SINADDR(a), &SINADDR(b), sizeof(SINADDR(a))) != 0) { |
1941 |
|
1826 |
return 0; |
1942 |
if (aa->sa_family == AF_INET6) { |
|
|
1943 |
if (memcmp(&((struct sockaddr_in6 *)aa)->sin6_addr, |
1944 |
&((struct sockaddr_in6 *)bb)->sin6_addr, |
1945 |
sizeof(struct sockaddr_in6)) != 0) return 0; |
1946 |
} else { |
1947 |
if (((struct sockaddr_in *)aa)->sin_addr.s_addr != |
1948 |
((struct sockaddr_in *)bb)->sin_addr.s_addr) return 0; |
1827 |
} |
1949 |
} |
|
|
1950 |
|
1828 |
return 1; |
1951 |
return 1; |
1829 |
} |
1952 |
} |
1830 |
|
1953 |
|
|
|
1954 |
#else |
1955 |
|
1956 |
static int ip_equal(const struct sockaddr *a, const struct sockaddr *b) |
1957 |
{ |
1958 |
daemon_assert(a != NULL); |
1959 |
daemon_assert(b != NULL); |
1960 |
daemon_assert(a->sa_family == AF_INET); |
1961 |
daemon_assert(b->sa_family == AF_INET); |
1962 |
|
1963 |
if (((struct sockaddr_in *)aa)->sin_addr.s_addr != |
1964 |
((struct sockaddr_in *)bb)->sin_addr.s_addr) return 0; |
1965 |
|
1966 |
return 1; |
1967 |
} |
1968 |
|
1969 |
#endif |