diff options
Diffstat (limited to 'usr.sbin/faithd')
-rw-r--r-- | usr.sbin/faithd/Makefile | 4 | ||||
-rw-r--r-- | usr.sbin/faithd/README | 5 | ||||
-rw-r--r-- | usr.sbin/faithd/faithd.8 | 96 | ||||
-rw-r--r-- | usr.sbin/faithd/faithd.c | 225 | ||||
-rw-r--r-- | usr.sbin/faithd/faithd.h | 4 | ||||
-rw-r--r-- | usr.sbin/faithd/ftp.c | 592 | ||||
-rw-r--r-- | usr.sbin/faithd/prefix.c | 31 | ||||
-rw-r--r-- | usr.sbin/faithd/rsh.c | 212 | ||||
-rw-r--r-- | usr.sbin/faithd/tcp.c | 25 | ||||
-rw-r--r-- | usr.sbin/faithd/test/faithd.rb | 2 |
10 files changed, 439 insertions, 757 deletions
diff --git a/usr.sbin/faithd/Makefile b/usr.sbin/faithd/Makefile index 29634c3..3d663b8 100644 --- a/usr.sbin/faithd/Makefile +++ b/usr.sbin/faithd/Makefile @@ -16,8 +16,8 @@ PROG= faithd MAN= faithd.8 -SRCS= faithd.c tcp.c ftp.c rsh.c prefix.c +SRCS= faithd.c tcp.c ftp.c prefix.c -#CFLAGS+= -DFAITH4 +CFLAGS= -DHAVE_POLL_H .include <bsd.prog.mk> diff --git a/usr.sbin/faithd/README b/usr.sbin/faithd/README index af0bfed..6628bf6 100644 --- a/usr.sbin/faithd/README +++ b/usr.sbin/faithd/README @@ -1,9 +1,10 @@ Configuring FAITH IPv6-to-IPv4 TCP relay Kazu Yamamoto and Jun-ichiro itojun Hagino -$KAME: README,v 1.8 2001/09/05 03:04:20 itojun Exp $ +$KAME: README,v 1.10 2003/01/06 21:40:33 sumikawa Exp $ $FreeBSD$ + Introduction ============ @@ -73,8 +74,6 @@ The following example assumes: More examples: - # faithd login /usr/libexec/rlogin rlogind - # faithd shell /usr/libexec/rshd rshd # faithd ftpd /usr/libexec/ftpd ftpd -l # faithd sshd diff --git a/usr.sbin/faithd/faithd.8 b/usr.sbin/faithd/faithd.8 index 177396b..66de665 100644 --- a/usr.sbin/faithd/faithd.8 +++ b/usr.sbin/faithd/faithd.8 @@ -1,4 +1,4 @@ -.\" $KAME: faithd.8,v 1.33 2001/09/05 03:04:20 itojun Exp $ +.\" $KAME: faithd.8,v 1.37 2002/05/09 14:21:23 itojun Exp $ .\" .\" Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. .\" All rights reserved. @@ -41,10 +41,12 @@ .Op Fl f Ar configfile .Ar service .Op Ar serverpath Op Ar serverargs +.Nm "" .Sh DESCRIPTION The .Nm -utility provides IPv6-to-IPv4 TCP relay. It +utility provides IPv6-to-IPv4 TCP relay. +.Nm must be used on an IPv4/v6 dual stack router. .Pp When @@ -65,7 +67,7 @@ destination. For example, if .Li 3ffe:0501:4819:ffff:: is reserved for -.Nm , +.Nm Ns , and the .Tn TCPv6 destination address is @@ -116,7 +118,6 @@ at .Pa http://www.vermicelli.pasta.cs.uit.no/ipv6/software.html . Make sure you do not propagate translated DNS records to normal DNS cloud, it is highly harmful. -.Pp .Ss Daemon mode When .Nm @@ -147,7 +148,7 @@ or other standard mechanisms. By specifying .Ar serverpath to -.Nm , +.Nm Ns , you can run local daemons on the router. The .Nm @@ -172,8 +173,6 @@ Use privileged TCP port number as source port, for IPv4 TCP connection toward final destination. For relaying .Xr ftp 1 -and -.Xr rlogin 1 , this flag is not necessary as special program code is supplied. .El .Pp @@ -184,9 +183,7 @@ It is capable of emulating TCP half close as well. The .Nm utility includes special support for protocols used by -.Xr ftp 1 -and -.Xr rlogin 1 . +.Xr ftp 1 . When translating FTP protocol, .Nm translates network level addresses in @@ -194,18 +191,11 @@ translates network level addresses in and .Li PASV/LPSV/EPSV commands. -For RLOGIN protocol, -.Nm -will relay back connection from -.Xr rlogind 8 -on the server to -.Xr rlogin 1 -on client. .Pp Inactive sessions will be disconnected in 30 minutes, to avoid stale sessions from chewing up resources. This may be inappropriate for some of the services -(should this be configurable?). +.Pq should this be configurable? . .Ss inetd mode When .Nm @@ -243,10 +233,12 @@ To prevent malicious accesses, implements a simple address-based access control. With .Pa /etc/faithd.conf -(or +.Po +or .Ar configfile specified by -.Fl f ) , +.Fl f +.Pc , .Nm will avoid relaying unwanted traffic. The @@ -254,35 +246,48 @@ The contains directives with the following format: .Bl -bullet .It -.Ar src Ns / Ns Ar slen Cm deny Ar dst Ns / Ns Ar dlen +.Xo +.Ic Ar src/slen Li deny Ar dst/dlen +.Xc .Pp If the source address of a query matches -.Ar src Ns / Ns Ar slen , +.Ar src/slen , and the translated destination address matches -.Ar dst Ns / Ns Ar dlen , +.Ar dst/dlen , deny the connection. .It -.Ar src Ns / Ns Ar slen Cm permit Ar dst Ns / Ns Ar dlen +.Xo +.Ic Ar src/slen Li permit Ar dst/dlen +.Xc .Pp If the source address of a query matches -.Ar src Ns / Ns Ar slen , +.Ar src/slen , and the translated destination address matches -.Ar dst Ns / Ns Ar dlen , +.Ar dst/dlen , permit the connection. .El .Pp The directives are evaluated in sequence, and the first matching entry will be effective. If there is no match -(if we reach the end of the ruleset) +.Pq if we reach the end of the ruleset the traffic will be denied. .Pp With inetd mode, traffic may be filtered by using access control functionality in .Xr inetd 8 . +.Sh RETURN VALUES +.Nm +exits with +.Dv EXIT_SUCCESS +.Pq 0 +on success, and +.Dv EXIT_FAILURE +.Pq 1 +on error. .Sh EXAMPLES Before invoking -.Nm , +.Nm Ns , .Xr faith 4 interface has to be configured properly. .Bd -literal -offset @@ -320,26 +325,19 @@ If you would like to pass extra arguments to the local daemon: Here are some other examples. You may need .Fl p -to translate rsh/rlogin services. +if the service checks the source port range. .Bd -literal -offset # faithd ssh -# faithd login /usr/libexec/rlogin rlogind -# faithd shell /usr/libexec/rshd rshd +# faithd telnet /usr/libexec/telnetd telnetd .Ed -.Pp -However, you should be careful when translating rlogin or rsh -connections. -See -.Sx SECURITY CONSIDERATIONS -for more details. .Ss inetd mode samples Add the following lines into .Xr inetd.conf 5 . Syntax may vary depending upon your operating system. .Bd -literal -offset -telnet stream tcp6/faith nowait root /usr/sbin/faithd telnetd -ftp stream tcp6/faith nowait root /usr/sbin/faithd ftpd -l -ssh stream tcp6/faith nowait root /usr/sbin/faithd /usr/sbin/sshd -i +telnet stream tcp6/faith nowait root faithd telnetd +ftp stream tcp6/faith nowait root faithd ftpd -l +ssh stream tcp6/faith nowait root faithd /usr/sbin/sshd -i .Ed .Pp .Xr inetd 8 @@ -370,16 +368,6 @@ setting. 3ffe:501:ffff::/48 deny 127.0.0.0/8 3ffe:501:ffff::/48 permit 0.0.0.0/0 .Ed -.Sh RETURN VALUES -The -.Nm -utility exits with -.Dv EXIT_SUCCESS -.Pq 0 -on success, and -.Dv EXIT_FAILURE -.Pq 1 -on error. .Sh SEE ALSO .Xr faith 4 , .Xr route 8 , @@ -403,11 +391,9 @@ IPv6 and IPsec support based on the KAME Project (http://www.kame.net/) stack was initially integrated into .Fx 4.0 .Sh SECURITY CONSIDERATIONS -It is very insecure to use -.Xr rhosts 5 -and other IP-address based authentication, for connections relayed by -.Nm -(and any other TCP relaying services). +It is very insecure to use IP-address based authentication, for connections relayed by +.Nm Ns , +and any other TCP relaying services. .Pp Administrators are advised to limit accesses to .Nm diff --git a/usr.sbin/faithd/faithd.c b/usr.sbin/faithd/faithd.c index 856f24a..3df90a5 100644 --- a/usr.sbin/faithd/faithd.c +++ b/usr.sbin/faithd/faithd.c @@ -1,4 +1,4 @@ -/* $KAME: faithd.c,v 1.46 2002/01/24 16:40:42 sumikawa Exp $ */ +/* $KAME: faithd.c,v 1.67 2003/10/16 05:26:21 itojun Exp $ */ /* * Copyright (C) 1997 and 1998 WIDE Project. @@ -46,10 +46,11 @@ #include <sys/stat.h> #include <sys/time.h> #include <sys/ioctl.h> -#ifdef __FreeBSD__ #include <libutil.h> -#endif +#ifdef HAVE_POLL_H +#include <poll.h> +#endif #include <stdio.h> #include <stdlib.h> #include <stdarg.h> @@ -74,14 +75,6 @@ #include <netdb.h> #include <ifaddrs.h> -#ifdef FAITH4 -#include <resolv.h> -#include <arpa/nameser.h> -#ifndef FAITH_NS -#define FAITH_NS "FAITH_NS" -#endif -#endif - #include "faithd.h" #include "prefix.h" @@ -90,11 +83,13 @@ char *serverarg[MAXARGV + 1]; static char *faithdname = NULL; char logname[BUFSIZ]; char procname[BUFSIZ]; + struct myaddrs { struct myaddrs *next; struct sockaddr *addr; }; struct myaddrs *myaddrs = NULL; + static const char *service; #ifdef USE_ROUTE static int sockfd = 0; @@ -111,9 +106,6 @@ static void play_service __P((int)); static void play_child __P((int, struct sockaddr *)); static int faith_prefix __P((struct sockaddr *)); static int map6to4 __P((struct sockaddr_in6 *, struct sockaddr_in *)); -#ifdef FAITH4 -static int map4to6 __P((struct sockaddr_in *, struct sockaddr_in6 *)); -#endif static void sig_child __P((int)); static void sig_terminate __P((int)); static void start_daemon __P((void)); @@ -151,7 +143,7 @@ inetd_main(int argc, char **argv) char path[MAXPATHLEN]; struct sockaddr_storage me; struct sockaddr_storage from; - int melen, fromlen; + socklen_t melen, fromlen; int i; int error; const int on = 1; @@ -228,11 +220,8 @@ daemon_main(int argc, char **argv) int s_wld, error, i, serverargc, on = 1; int family = AF_INET6; int c; -#ifdef FAITH_NS - char *ns; -#endif /* FAITH_NS */ - while ((c = getopt(argc, argv, "df:p46")) != -1) { + while ((c = getopt(argc, argv, "df:p")) != -1) { switch (c) { case 'd': dflag++; @@ -243,14 +232,6 @@ daemon_main(int argc, char **argv) case 'p': pflag++; break; -#ifdef FAITH4 - case '4': - family = AF_INET; - break; - case '6': - family = AF_INET6; - break; -#endif default: usage(); /*NOTREACHED*/ @@ -264,23 +245,6 @@ daemon_main(int argc, char **argv) /*NOTREACHED*/ } -#ifdef FAITH_NS - if ((ns = getenv(FAITH_NS)) != NULL) { - struct sockaddr_storage ss; - struct addrinfo hints, *res; - char serv[NI_MAXSERV]; - - memset(&ss, 0, sizeof(ss)); - memset(&hints, 0, sizeof(hints)); - snprintf(serv, sizeof(serv), "%u", NAMESERVER_PORT); - hints.ai_flags = AI_NUMERICHOST; - if (getaddrinfo(ns, serv, &hints, &res) == 0) { - res_init(); - memcpy(&_res_ext.nsaddr, res->ai_addr, res->ai_addrlen); - _res.nscount = 1; - } - } -#endif /* FAITH_NS */ #ifdef USE_ROUTE grab_myaddrs(); @@ -295,11 +259,13 @@ daemon_main(int argc, char **argv) if (serverargc >= MAXARGV) exit_stderr("too many arguments"); - serverpath = malloc(strlen(argv[NUMPRG]) + 1); - strcpy(serverpath, argv[NUMPRG]); + serverpath = strdup(argv[NUMPRG]); + if (!serverpath) + exit_stderr("not enough core"); for (i = 0; i < serverargc; i++) { - serverarg[i] = malloc(strlen(argv[i + NUMARG]) + 1); - strcpy(serverarg[i], argv[i + NUMARG]); + serverarg[i] = strdup(argv[i + NUMARG]); + if (!serverarg[i]) + exit_stderr("not enough core"); } serverarg[i] = NULL; /* fall throuth */ @@ -308,6 +274,8 @@ daemon_main(int argc, char **argv) break; } + start_daemon(); + /* * Opening wild card socket for this service. */ @@ -316,7 +284,7 @@ daemon_main(int argc, char **argv) hints.ai_flags = AI_PASSIVE; hints.ai_family = family; hints.ai_socktype = SOCK_STREAM; - hints.ai_protocol = 0; + hints.ai_protocol = IPPROTO_TCP; /* SCTP? */ error = getaddrinfo(NULL, service, &hints, &res); if (error) exit_failure("getaddrinfo: %s", gai_strerror(error)); @@ -333,16 +301,6 @@ daemon_main(int argc, char **argv) strerror(errno)); } #endif -#ifdef FAITH4 -#ifdef IP_FAITH - if (res->ai_family == AF_INET) { - error = setsockopt(s_wld, IPPROTO_IP, IP_FAITH, &on, sizeof(on)); - if (error == -1) - exit_failure("setsockopt(IP_FAITH): %s", - strerror(errno)); - } -#endif -#endif /* FAITH4 */ error = setsockopt(s_wld, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); if (error == -1) @@ -352,6 +310,12 @@ daemon_main(int argc, char **argv) if (error == -1) exit_failure("setsockopt(SO_OOBINLINE): %s", strerror(errno)); +#ifdef IPV6_V6ONLY + error = setsockopt(s_wld, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)); + if (error == -1) + exit_failure("setsockopt(IPV6_V6ONLY): %s", strerror(errno)); +#endif + error = bind(s_wld, (struct sockaddr *)res->ai_addr, res->ai_addrlen); if (error == -1) exit_failure("bind: %s", strerror(errno)); @@ -372,8 +336,6 @@ daemon_main(int argc, char **argv) * Everything is OK. */ - start_daemon(); - snprintf(logname, sizeof(logname), "faithd %s", service); snprintf(procname, sizeof(procname), "accepting port %s", service); openlog(logname, LOG_PID | LOG_NOWAIT, LOG_DAEMON); @@ -388,12 +350,16 @@ static void play_service(int s_wld) { struct sockaddr_storage srcaddr; - int len; + socklen_t len; int s_src; pid_t child_pid; +#ifdef HAVE_POLL_H + struct pollfd pfd[2]; +#else fd_set rfds; - int error; int maxfd; +#endif + int error; /* * Wait, accept, fork, faith.... @@ -401,17 +367,37 @@ play_service(int s_wld) again: setproctitle("%s", procname); +#ifdef HAVE_POLL_H + pfd[0].fd = s_wld; + pfd[0].events = POLLIN; + pfd[1].fd = -1; + pfd[1].revents = 0; +#else FD_ZERO(&rfds); + if (s_wld >= FD_SETSIZE) + exit_failure("descriptor too big"); FD_SET(s_wld, &rfds); maxfd = s_wld; +#endif #ifdef USE_ROUTE if (sockfd) { +#ifdef HAVE_POLL_H + pfd[1].fd = sockfd; + pfd[1].events = POLLIN; +#else + if (sockfd >= FD_SETSIZE) + exit_failure("descriptor too big"); FD_SET(sockfd, &rfds); maxfd = (maxfd < sockfd) ? sockfd : maxfd; +#endif } #endif +#ifdef HAVE_POLL_H + error = poll(pfd, sizeof(pfd)/sizeof(pfd[0]), INFTIM); +#else error = select(maxfd + 1, &rfds, NULL, NULL, NULL); +#endif if (error < 0) { if (errno == EINTR) goto again; @@ -420,23 +406,38 @@ again: } #ifdef USE_ROUTE - if (FD_ISSET(sockfd, &rfds)) { +#ifdef HAVE_POLL_H + if (pfd[1].revents & POLLIN) +#else + if (FD_ISSET(sockfd, &rfds)) +#endif + { update_myaddrs(); } #endif - if (FD_ISSET(s_wld, &rfds)) { +#ifdef HAVE_POLL_H + if (pfd[0].revents & POLLIN) +#else + if (FD_ISSET(s_wld, &rfds)) +#endif + { len = sizeof(srcaddr); - s_src = accept(s_wld, (struct sockaddr *)&srcaddr, - &len); + s_src = accept(s_wld, (struct sockaddr *)&srcaddr, &len); if (s_src < 0) { if (errno == ECONNABORTED) goto again; exit_failure("socket: %s", strerror(errno)); /*NOTREACHED*/ } + if (srcaddr.ss_family == AF_INET6 && + IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)&srcaddr)->sin6_addr)) { + close(s_src); + syslog(LOG_ERR, "connection from IPv4 mapped address?"); + goto again; + } child_pid = fork(); - + if (child_pid == 0) { /* child process */ close(s_wld); @@ -463,7 +464,7 @@ play_child(int s_src, struct sockaddr *srcaddr) char src[NI_MAXHOST]; char dst6[NI_MAXHOST]; char dst4[NI_MAXHOST]; - int len = sizeof(dstaddr6); + socklen_t len = sizeof(dstaddr6); int s_dst, error, hport, nresvport, on = 1; struct timeval tv; struct sockaddr *sa4; @@ -473,7 +474,7 @@ play_child(int s_src, struct sockaddr *srcaddr) tv.tv_usec = 0; getnameinfo(srcaddr, srcaddr->sa_len, - src, sizeof(src), NULL, 0, NI_NUMERICHOST); + src, sizeof(src), NULL, 0, NI_NUMERICHOST); syslog(LOG_INFO, "accepted a client from %s", src); error = getsockname(s_src, (struct sockaddr *)&dstaddr6, &len); @@ -483,7 +484,7 @@ play_child(int s_src, struct sockaddr *srcaddr) } getnameinfo((struct sockaddr *)&dstaddr6, len, - dst6, sizeof(dst6), NULL, 0, NI_NUMERICHOST); + dst6, sizeof(dst6), NULL, 0, NI_NUMERICHOST); syslog(LOG_INFO, "the client is connecting to %s", dst6); if (!faith_prefix((struct sockaddr *)&dstaddr6)) { @@ -522,17 +523,6 @@ play_child(int s_src, struct sockaddr *srcaddr) } syslog(LOG_INFO, "translating from v6 to v4"); break; -#ifdef FAITH4 - case AF_INET: - if (!map4to6((struct sockaddr_in *)&dstaddr6, - (struct sockaddr_in6 *)&dstaddr4)) { - close(s_src); - exit_failure("map4to6 failed"); - /*NOTREACHED*/ - } - syslog(LOG_INFO, "translating from v4 to v6"); - break; -#endif default: close(s_src); exit_failure("family not supported"); @@ -541,7 +531,7 @@ play_child(int s_src, struct sockaddr *srcaddr) sa4 = (struct sockaddr *)&dstaddr4; getnameinfo(sa4, sa4->sa_len, - dst4, sizeof(dst4), NULL, 0, NI_NUMERICHOST); + dst4, sizeof(dst4), NULL, 0, NI_NUMERICHOST); conf = config_match(srcaddr, sa4); if (!conf || !conf->permit) { @@ -565,18 +555,10 @@ play_child(int s_src, struct sockaddr *srcaddr) else /* AF_INET */ hport = ntohs(((struct sockaddr_in *)&dstaddr4)->sin_port); - switch (hport) { - case RLOGIN_PORT: - case RSH_PORT: + if (pflag) s_dst = rresvport_af(&nresvport, sa4->sa_family); - break; - default: - if (pflag) - s_dst = rresvport_af(&nresvport, sa4->sa_family); - else - s_dst = socket(sa4->sa_family, SOCK_STREAM, 0); - break; - } + else + s_dst = socket(sa4->sa_family, SOCK_STREAM, 0); if (s_dst < 0) { exit_failure("socket: %s", strerror(errno)); /*NOTREACHED*/ @@ -617,15 +599,6 @@ play_child(int s_src, struct sockaddr *srcaddr) case FTP_PORT: ftp_relay(s_src, s_dst); break; - case RSH_PORT: - syslog(LOG_WARNING, - "WARINNG: it is insecure to relay rsh port"); - rsh_relay(s_src, s_dst); - break; - case RLOGIN_PORT: - syslog(LOG_WARNING, - "WARINNG: it is insecure to relay rlogin port"); - /*FALLTHROUGH*/ default: tcp_relay(s_src, s_dst, service); break; @@ -657,7 +630,7 @@ faith_prefix(struct sockaddr *dst) } if (memcmp(dst, &faith_prefix, - sizeof(struct in6_addr) - sizeof(struct in_addr) == 0) { + sizeof(struct in6_addr) - sizeof(struct in_addr) == 0) { return 1; } return 0; @@ -727,39 +700,6 @@ map6to4(struct sockaddr_in6 *dst6, struct sockaddr_in *dst4) return 1; } -#ifdef FAITH4 -/* 0: non faith, 1: faith */ -static int -map4to6(struct sockaddr_in *dst4, struct sockaddr_in6 *dst6) -{ - char host[NI_MAXHOST]; - char serv[NI_MAXSERV]; - struct addrinfo hints, *res; - int ai_errno; - - if (getnameinfo((struct sockaddr *)dst4, dst4->sin_len, host, sizeof(host), - serv, sizeof(serv), NI_NAMEREQD|NI_NUMERICSERV) != 0) - return 0; - - memset(&hints, 0, sizeof(hints)); - hints.ai_flags = 0; - hints.ai_family = AF_INET6; - hints.ai_socktype = SOCK_STREAM; - hints.ai_protocol = 0; - - if ((ai_errno = getaddrinfo(host, serv, &hints, &res)) != 0) { - syslog(LOG_INFO, "%s %s: %s", host, serv, - gai_strerror(ai_errno)); - return 0; - } - - memcpy(dst6, res->ai_addr, res->ai_addrlen); - - freeaddrinfo(res); - - return 1; -} -#endif /* FAITH4 */ static void sig_child(int sig) @@ -767,9 +707,10 @@ sig_child(int sig) int status; pid_t pid; - pid = wait3(&status, WNOHANG, (struct rusage *)0); - if (pid && WEXITSTATUS(status)) - syslog(LOG_WARNING, "child %d exit status 0x%x", pid, status); + while ((pid = wait3(&status, WNOHANG, (struct rusage *)0)) > 0) + if (WEXITSTATUS(status)) + syslog(LOG_WARNING, "child %ld exit status 0x%x", + (long)pid, status); } void @@ -894,8 +835,8 @@ grab_myaddrs() if (dflag) { char hbuf[NI_MAXHOST]; getnameinfo(p->addr, p->addr->sa_len, - hbuf, sizeof(hbuf), NULL, 0, - NI_NUMERICHOST); + hbuf, sizeof(hbuf), NULL, 0, + NI_NUMERICHOST); syslog(LOG_INFO, "my interface: %s %s", hbuf, ifa->ifa_name); } diff --git a/usr.sbin/faithd/faithd.h b/usr.sbin/faithd/faithd.h index 0efb2b8..f422432 100644 --- a/usr.sbin/faithd/faithd.h +++ b/usr.sbin/faithd/faithd.h @@ -1,4 +1,4 @@ -/* $KAME: faithd.h,v 1.8 2001/09/05 03:04:21 itojun Exp $ */ +/* $KAME: faithd.h,v 1.9 2002/05/09 09:41:24 itojun Exp $ */ /* * Copyright (C) 1997 and 1998 WIDE Project. @@ -38,8 +38,6 @@ extern void tcp_relay __P((int, int, const char *)); extern void ftp_relay __P((int, int)); extern int ftp_active __P((int, int, int *, int *)); extern int ftp_passive __P((int, int, int *, int *)); -extern void rsh_relay __P((int, int)); -extern void rsh_dual_relay __P((int, int)); extern void exit_success __P((const char *, ...)) __attribute__((__format__(__printf__, 1, 2))); extern void exit_failure __P((const char *, ...)) diff --git a/usr.sbin/faithd/ftp.c b/usr.sbin/faithd/ftp.c index 5664681..6ceb24d 100644 --- a/usr.sbin/faithd/ftp.c +++ b/usr.sbin/faithd/ftp.c @@ -1,4 +1,4 @@ -/* $KAME: ftp.c,v 1.11 2001/07/02 14:36:49 itojun Exp $ */ +/* $KAME: ftp.c,v 1.23 2003/08/19 21:20:33 itojun Exp $ */ /* * Copyright (C) 1997 and 1998 WIDE Project. @@ -42,6 +42,9 @@ #include <string.h> #include <syslog.h> #include <unistd.h> +#ifdef HAVE_POLL_H +#include <poll.h> +#endif #include <errno.h> #include <ctype.h> @@ -62,11 +65,7 @@ static struct sockaddr_storage data4; /* server data address */ static struct sockaddr_storage data6; /* client data address */ static int epsvall = 0; -#ifdef FAITH4 -enum state { NONE, LPRT, EPRT, PORT, LPSV, EPSV, PASV }; -#else enum state { NONE, LPRT, EPRT, LPSV, EPSV }; -#endif static int ftp_activeconn __P((void)); static int ftp_passiveconn __P((void)); @@ -77,7 +76,11 @@ static int ftp_copycommand __P((int, int, enum state *)); void ftp_relay(int ctl6, int ctl4) { +#ifdef HAVE_POLL_H + struct pollfd pfd[6]; +#else fd_set readfds; +#endif int error; enum state state = NONE; struct timeval tv; @@ -85,25 +88,90 @@ ftp_relay(int ctl6, int ctl4) syslog(LOG_INFO, "starting ftp control connection"); for (;;) { +#ifdef HAVE_POLL_H + pfd[0].fd = ctl4; + pfd[0].events = POLLIN; + pfd[1].fd = ctl6; + pfd[1].events = POLLIN; + if (0 <= port4) { + pfd[2].fd = port4; + pfd[2].events = POLLIN; + } else + pfd[2].fd = -1; + if (0 <= port6) { + pfd[3].fd = port6; + pfd[3].events = POLLIN; + } else + pfd[3].fd = -1; +#if 0 + if (0 <= wport4) { + pfd[4].fd = wport4; + pfd[4].events = POLLIN; + } else + pfd[4].fd = -1; + if (0 <= wport6) { + pfd[5].fd = wport4; + pfd[5].events = POLLIN; + } else + pfd[5].fd = -1; +#else + pfd[4].fd = pfd[5].fd = -1; + pfd[4].events = pfd[5].events = 0; +#endif +#else + int maxfd = 0; + FD_ZERO(&readfds); + if (ctl4 >= FD_SETSIZE) + exit_failure("descriptor too big"); FD_SET(ctl4, &readfds); + maxfd = ctl4; + if (ctl6 >= FD_SETSIZE) + exit_failure("descriptor too big"); FD_SET(ctl6, &readfds); - if (0 <= port4) + maxfd = (ctl6 > maxfd) ? ctl6 : maxfd; + if (0 <= port4) { + if (port4 >= FD_SETSIZE) + exit_failure("descriptor too big"); FD_SET(port4, &readfds); - if (0 <= port6) + maxfd = (port4 > maxfd) ? port4 : maxfd; + } + if (0 <= port6) { + if (port6 >= FD_SETSIZE) + exit_failure("descriptor too big"); FD_SET(port6, &readfds); + maxfd = (port6 > maxfd) ? port6 : maxfd; + } #if 0 - if (0 <= wport4) + if (0 <= wport4) { + if (wport4 >= FD_SETSIZE) + exit_failure("descriptor too big"); FD_SET(wport4, &readfds); - if (0 <= wport6) + maxfd = (wport4 > maxfd) ? wport4 : maxfd; + } + if (0 <= wport6) { + if (wport6 >= FD_SETSIZE) + exit_failure("descriptor too big"); FD_SET(wport6, &readfds); + maxfd = (wport6 > maxfd) ? wport6 : maxfd; + } +#endif #endif tv.tv_sec = FAITH_TIMEOUT; tv.tv_usec = 0; - error = select(256, &readfds, NULL, NULL, &tv); - if (error == -1) +#ifdef HAVE_POLL_H + error = poll(pfd, sizeof(pfd)/sizeof(pfd[0]), tv.tv_sec * 1000); +#else + error = select(maxfd + 1, &readfds, NULL, NULL, &tv); +#endif + if (error == -1) { +#ifdef HAVE_POLL_H + exit_failure("poll: %s", strerror(errno)); +#else exit_failure("select: %s", strerror(errno)); +#endif + } else if (error == 0) exit_failure("connection timeout"); @@ -113,7 +181,12 @@ ftp_relay(int ctl6, int ctl4) * otherwise some of the pipe may become full and we cannot * relay correctly. */ - if (FD_ISSET(ctl6, &readfds)) { +#ifdef HAVE_POLL_H + if (pfd[1].revents & POLLIN) +#else + if (FD_ISSET(ctl6, &readfds)) +#endif + { /* * copy control connection from the client. * command translation is necessary. @@ -126,9 +199,15 @@ ftp_relay(int ctl6, int ctl4) close(ctl4); close(ctl6); exit_success("terminating ftp control connection"); + /*NOTREACHED*/ } } - if (FD_ISSET(ctl4, &readfds)) { +#ifdef HAVE_POLL_H + if (pfd[0].revents & POLLIN) +#else + if (FD_ISSET(ctl4, &readfds)) +#endif + { /* * copy control connection from the server * translation of result code is necessary. @@ -141,14 +220,24 @@ ftp_relay(int ctl6, int ctl4) close(ctl4); close(ctl6); exit_success("terminating ftp control connection"); + /*NOTREACHED*/ } } - if (0 <= port4 && 0 <= port6 && FD_ISSET(port4, &readfds)) { +#ifdef HAVE_POLL_H + if (0 <= port4 && 0 <= port6 && (pfd[2].revents & POLLIN)) +#else + if (0 <= port4 && 0 <= port6 && FD_ISSET(port4, &readfds)) +#endif + { /* * copy data connection. * no special treatment necessary. */ +#ifdef HAVE_POLL_H + if (pfd[2].revents & POLLIN) +#else if (FD_ISSET(port4, &readfds)) +#endif error = ftp_copy(port4, port6); switch (error) { case -1: @@ -163,12 +252,21 @@ ftp_relay(int ctl6, int ctl4) break; } } - if (0 <= port4 && 0 <= port6 && FD_ISSET(port6, &readfds)) { +#ifdef HAVE_POLL_H + if (0 <= port4 && 0 <= port6 && (pfd[3].revents & POLLIN)) +#else + if (0 <= port4 && 0 <= port6 && FD_ISSET(port6, &readfds)) +#endif + { /* * copy data connection. * no special treatment necessary. */ +#ifdef HAVE_POLL_H + if (pfd[3].revents & POLLIN) +#else if (FD_ISSET(port6, &readfds)) +#endif error = ftp_copy(port6, port4); switch (error) { case -1: @@ -184,13 +282,23 @@ ftp_relay(int ctl6, int ctl4) } } #if 0 - if (wport4 && FD_ISSET(wport4, &readfds)) { +#ifdef HAVE_POLL_H + if (wport4 && (pfd[4].revents & POLLIN)) +#else + if (wport4 && FD_ISSET(wport4, &readfds)) +#endif + { /* * establish active data connection from the server. */ ftp_activeconn(); } - if (wport6 && FD_ISSET(wport6, &readfds)) { +#ifdef HAVE_POLL_H + if (wport4 && (pfd[5].revents & POLLIN)) +#else + if (wport6 && FD_ISSET(wport6, &readfds)) +#endif + { /* * establish passive data connection from the client. */ @@ -206,20 +314,37 @@ ftp_relay(int ctl6, int ctl4) static int ftp_activeconn() { - int n; + socklen_t n; int error; +#ifdef HAVE_POLL_H + struct pollfd pfd[1]; +#else fd_set set; +#endif struct timeval timeout; struct sockaddr *sa; /* get active connection from server */ +#ifdef HAVE_POLL_H + pfd[0].fd = wport4; + pfd[0].events = POLLIN; +#else FD_ZERO(&set); + if (wport4 >= FD_SETSIZE) + exit_failure("descriptor too big"); FD_SET(wport4, &set); +#endif timeout.tv_sec = 120; - timeout.tv_usec = -1; + timeout.tv_usec = 0; n = sizeof(data4); - if (select(wport4 + 1, &set, NULL, NULL, &timeout) == 0 - || (port4 = accept(wport4, (struct sockaddr *)&data4, &n)) < 0) { +#ifdef HAVE_POLL_H + if (poll(pfd, sizeof(pfd)/sizeof(pfd[0]), timeout.tv_sec * 1000) == 0 || + (port4 = accept(wport4, (struct sockaddr *)&data4, &n)) < 0) +#else + if (select(wport4 + 1, &set, NULL, NULL, &timeout) == 0 || + (port4 = accept(wport4, (struct sockaddr *)&data4, &n)) < 0) +#endif + { close(wport4); wport4 = -1; syslog(LOG_INFO, "active mode data connection failed"); @@ -253,20 +378,37 @@ ftp_activeconn() static int ftp_passiveconn() { - int n; + socklen_t len; int error; +#ifdef HAVE_POLL_H + struct pollfd pfd[1]; +#else fd_set set; +#endif struct timeval timeout; struct sockaddr *sa; /* get passive connection from client */ +#ifdef HAVE_POLL_H + pfd[0].fd = wport6; + pfd[0].events = POLLIN; +#else FD_ZERO(&set); + if (wport6 >= FD_SETSIZE) + exit_failure("descriptor too big"); FD_SET(wport6, &set); +#endif timeout.tv_sec = 120; timeout.tv_usec = 0; - n = sizeof(data6); - if (select(wport6 + 1, &set, NULL, NULL, &timeout) == 0 - || (port6 = accept(wport6, (struct sockaddr *)&data6, &n)) < 0) { + len = sizeof(data6); +#ifdef HAVE_POLL_H + if (poll(pfd, sizeof(pfd)/sizeof(pfd[0]), timeout.tv_sec * 1000) == 0 || + (port6 = accept(wport6, (struct sockaddr *)&data6, &len)) < 0) +#else + if (select(wport6 + 1, &set, NULL, NULL, &timeout) == 0 || + (port6 = accept(wport6, (struct sockaddr *)&data6, &len)) < 0) +#endif + { close(wport6); wport6 = -1; syslog(LOG_INFO, "passive mode data connection failed"); @@ -300,8 +442,7 @@ ftp_passiveconn() static int ftp_copy(int src, int dst) { - int error, atmark; - int n; + int error, atmark, n; /* OOB data handling */ error = ioctl(src, SIOCATMARK, &atmark); @@ -338,10 +479,12 @@ ftp_copy(int src, int dst) static int ftp_copyresult(int src, int dst, enum state state) { - int error, atmark; - int n; + int error, atmark, n; + socklen_t len; char *param; int code; + char *a, *p; + int i; /* OOB data handling */ error = ioctl(src, SIOCATMARK, &atmark); @@ -367,10 +510,6 @@ ftp_copyresult(int src, int dst, enum state state) /* * parse argument */ - { - char *p; - int i; - p = rbuf; for (i = 0; i < 3; i++) { if (!isdigit(*p)) { @@ -392,7 +531,6 @@ ftp_copyresult(int src, int dst, enum state state) param++; if (!*param) param = NULL; - } switch (state) { case NONE: @@ -400,15 +538,17 @@ ftp_copyresult(int src, int dst, enum state state) if (ftp_activeconn() < 0) { n = snprintf(rbuf, sizeof(rbuf), "425 Cannot open data connetion\r\n"); + if (n < 0 || n >= sizeof(rbuf)) + n = 0; } } - return n > 0 ? write(dst, rbuf, n) : n; + if (n) + write(dst, rbuf, n); + return n; case LPRT: case EPRT: /* expecting "200 PORT command successful." */ if (code == 200) { - char *p; - p = strstr(rbuf, "PORT"); if (p) { p[0] = (state == LPRT) ? 'L' : 'E'; @@ -420,24 +560,6 @@ ftp_copyresult(int src, int dst, enum state state) } write(dst, rbuf, n); return n; -#ifdef FAITH4 - case PORT: - /* expecting "200 EPRT command successful." */ - if (code == 200) { - char *p; - - p = strstr(rbuf, "EPRT"); - if (p) { - p[0] = 'P'; - p[1] = 'O'; - } - } else { - close(wport4); - wport4 = -1; - } - write(dst, rbuf, n); - return n; -#endif case LPSV: case EPSV: /* @@ -457,7 +579,6 @@ passivefail0: struct sockaddr_in *sin; struct sockaddr_in6 *sin6; u_short port; - char *p; /* * PASV result -> LPSV/EPSV result @@ -496,7 +617,11 @@ passivefail0: passivefail: n = snprintf(sbuf, sizeof(sbuf), "500 could not translate from PASV\r\n"); - return n > 0 ? write(src, sbuf, n) : n; + if (n < 0 || n >= sizeof(sbuf)) + n = 0; + if (n) + write(src, sbuf, n); + return n; } #ifdef IPV6_FAITH { @@ -524,8 +649,8 @@ passivefail: /* * addr from dst, port from wport6 */ - n = sizeof(data6); - error = getsockname(wport6, (struct sockaddr *)&data6, &n); + len = sizeof(data6); + error = getsockname(wport6, (struct sockaddr *)&data6, &len); if (error == -1) { close(wport6); wport6 = -1; @@ -534,8 +659,8 @@ passivefail: sin6 = (struct sockaddr_in6 *)&data6; port = sin6->sin6_port; - n = sizeof(data6); - error = getsockname(dst, (struct sockaddr *)&data6, &n); + len = sizeof(data6); + error = getsockname(dst, (struct sockaddr *)&data6, &len); if (error == -1) { close(wport6); wport6 = -1; @@ -545,8 +670,6 @@ passivefail: sin6->sin6_port = port; if (state == LPSV) { - char *a, *p; - a = (char *)&sin6->sin6_addr; p = (char *)&sin6->sin6_port; n = snprintf(sbuf, sizeof(sbuf), @@ -556,132 +679,24 @@ passivefail: UC(a[8]), UC(a[9]), UC(a[10]), UC(a[11]), UC(a[12]), UC(a[13]), UC(a[14]), UC(a[15]), 2, UC(p[0]), UC(p[1])); - if (n > 0) - n = write(dst, sbuf, n); + if (n < 0 || n >= sizeof(sbuf)) + n = 0; + if (n) + write(dst, sbuf, n); passivemode = 1; return n; } else { n = snprintf(sbuf, sizeof(sbuf), "229 Entering Extended Passive Mode (|||%d|)\r\n", ntohs(sin6->sin6_port)); - if (n > 0) - n = write(dst, sbuf, n); + if (n < 0 || n >= sizeof(sbuf)) + n = 0; + if (n) + write(dst, sbuf, n); passivemode = 1; return n; } } -#ifdef FAITH4 - case PASV: - /* expecting "229 Entering Extended Passive Mode (|||x|)" */ - if (code != 229) { -passivefail1: - close(wport6); - wport6 = -1; - write(dst, rbuf, n); - return n; - } - - { - u_short port; - char *p; - struct sockaddr_in *sin; - struct sockaddr_in6 *sin6; - - /* - * EPSV result -> PORT result - */ - p = param; - while (*p && *p != '(') /*)*/ - p++; - if (!*p) - goto passivefail1; /*XXX*/ - p++; - n = sscanf(p, "|||%hu|", &port); - if (n != 1) - goto passivefail1; /*XXX*/ - - /* keep EPRT parameter */ - n = sizeof(data4); - error = getpeername(src, (struct sockaddr *)&data4, &n); - if (error == -1) - goto passivefail1; /*XXX*/ - sin6 = (struct sockaddr_in6 *)&data4; - sin6->sin6_port = htons(port); - - /* get ready for passive data connection */ - memset(&data6, 0, sizeof(data6)); - sin = (struct sockaddr_in *)&data6; - sin->sin_len = sizeof(*sin); - sin->sin_family = AF_INET; - wport6 = socket(sin->sin_family, SOCK_STREAM, 0); - if (wport6 == -1) { -passivefail2: - n = snprintf(sbuf, sizeof(sbuf), - "500 could not translate from EPSV\r\n"); - return n > 0 ? write(src, sbuf, n) : n; - } -#ifdef IP_FAITH - { - int on = 1; - error = setsockopt(wport6, IPPROTO_IP, IP_FAITH, - &on, sizeof(on)); - if (error == -1) - exit_error("setsockopt(IP_FAITH): %s", strerror(errno)); - } -#endif - error = bind(wport6, (struct sockaddr *)sin, sin->sin_len); - if (error == -1) { - close(wport6); - wport6 = -1; - goto passivefail2; - } - error = listen(wport6, 1); - if (error == -1) { - close(wport6); - wport6 = -1; - goto passivefail2; - } - - /* transmit PORT */ - /* - * addr from dst, port from wport6 - */ - n = sizeof(data6); - error = getsockname(wport6, (struct sockaddr *)&data6, &n); - if (error == -1) { - close(wport6); - wport6 = -1; - goto passivefail2; - } - sin = (struct sockaddr_in *)&data6; - port = sin->sin_port; - - n = sizeof(data6); - error = getsockname(dst, (struct sockaddr *)&data6, &n); - if (error == -1) { - close(wport6); - wport6 = -1; - goto passivefail2; - } - sin = (struct sockaddr_in *)&data6; - sin->sin_port = port; - - { - char *a, *p; - - a = (char *)&sin->sin_addr; - p = (char *)&sin->sin_port; - n = snprintf(sbuf, sizeof(sbuf), -"227 Entering Passive Mode (%d,%d,%d,%d,%d,%d)\r\n", - UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]), - UC(p[0]), UC(p[1])); - if (n > 0) - n = write(dst, sbuf, n); - passivemode = 1; - return n; - } - } -#endif /* FAITH4 */ } bad: @@ -693,15 +708,16 @@ passivefail2: static int ftp_copycommand(int src, int dst, enum state *state) { - int error, atmark; - int n; + int error, atmark, n; + socklen_t len; unsigned int af, hal, ho[16], pal, po[2]; - char *a, *p; + char *a, *p, *q; char cmd[5], *param; struct sockaddr_in *sin; struct sockaddr_in6 *sin6; enum state nstate; char ch; + int i; /* OOB data handling */ error = ioctl(src, SIOCATMARK, &atmark); @@ -732,10 +748,6 @@ ftp_copycommand(int src, int dst, enum state *state) /* * parse argument */ - { - char *p, *q; - int i; - p = rbuf; q = cmd; for (i = 0; i < 4; i++) { @@ -759,7 +771,6 @@ ftp_copycommand(int src, int dst, enum state *state) param++; if (!*param) param = NULL; - } *state = NONE; @@ -778,7 +789,11 @@ ftp_copycommand(int src, int dst, enum state *state) if (epsvall) { n = snprintf(sbuf, sizeof(sbuf), "501 %s disallowed in EPSV ALL\r\n", cmd); - return n > 0 ? write(src, sbuf, n) : n; + if (n < 0 || n >= sizeof(sbuf)) + n = 0; + if (n) + write(src, sbuf, n); + return n; } n = sscanf(param, @@ -791,7 +806,11 @@ ftp_copycommand(int src, int dst, enum state *state) if (n != 21 || af != 6 || hal != 16|| pal != 2) { n = snprintf(sbuf, sizeof(sbuf), "501 illegal parameter to LPRT\r\n"); - return n > 0 ? write(src, sbuf, n) : n; + if (n < 0 || n >= sizeof(sbuf)) + n = 0; + if (n) + write(src, sbuf, n); + return n; } /* keep LPRT parameter */ @@ -805,13 +824,17 @@ ftp_copycommand(int src, int dst, enum state *state) sendport: /* get ready for active data connection */ - n = sizeof(data4); - error = getsockname(dst, (struct sockaddr *)&data4, &n); + len = sizeof(data4); + error = getsockname(dst, (struct sockaddr *)&data4, &len); if (error == -1) { lprtfail: n = snprintf(sbuf, sizeof(sbuf), "500 could not translate to PORT\r\n"); - return n > 0 ? write(src, sbuf, n) : n; + if (n < 0 || n >= sizeof(sbuf)) + n = 0; + if (n) + write(src, sbuf, n); + return n; } if (((struct sockaddr *)&data4)->sa_family != AF_INET) goto lprtfail; @@ -834,8 +857,8 @@ lprtfail: } /* transmit PORT */ - n = sizeof(data4); - error = getsockname(wport4, (struct sockaddr *)&data4, &n); + len = sizeof(data4); + error = getsockname(wport4, (struct sockaddr *)&data4, &len); if (error == -1) { close(wport4); wport4 = -1; @@ -852,8 +875,10 @@ lprtfail: n = snprintf(sbuf, sizeof(sbuf), "PORT %d,%d,%d,%d,%d,%d\r\n", UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]), UC(p[0]), UC(p[1])); - if (n > 0) - n = write(dst, sbuf, n); + if (n < 0 || n >= sizeof(sbuf)) + n = 0; + if (n) + write(dst, sbuf, n); *state = nstate; passivemode = 0; return n; @@ -875,7 +900,11 @@ lprtfail: if (epsvall) { n = snprintf(sbuf, sizeof(sbuf), "501 %s disallowed in EPSV ALL\r\n", cmd); - return n > 0 ? write(src, sbuf, n) : n; + if (n < 0 || n >= sizeof(sbuf)) + n = 0; + if (n) + write(src, sbuf, n); + return n; } p = param; @@ -887,7 +916,11 @@ lprtfail: eprtparamfail: n = snprintf(sbuf, sizeof(sbuf), "501 illegal parameter to EPRT\r\n"); - return n > 0 ? write(src, sbuf, n) : n; + if (n < 0 || n >= sizeof(sbuf)) + n = 0; + if (n) + write(src, sbuf, n); + return n; } *p++ = '\0'; hostp = p; @@ -907,21 +940,34 @@ eprtparamfail: if (n != 1 || af != 2) { n = snprintf(sbuf, sizeof(sbuf), "501 unsupported address family to EPRT\r\n"); - return n > 0 ? write(src, sbuf, n) : n; + if (n < 0 || n >= sizeof(sbuf)) + n = 0; + if (n) + write(src, sbuf, n); + return n; } memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = IPPROTO_TCP; error = getaddrinfo(hostp, portp, &hints, &res); if (error) { n = snprintf(sbuf, sizeof(sbuf), "501 EPRT: %s\r\n", gai_strerror(error)); - return n > 0 ? write(src, sbuf, n) : n; + if (n < 0 || n >= sizeof(sbuf)) + n = 0; + if (n) + write(src, sbuf, n); + return n; } if (res->ai_next) { n = snprintf(sbuf, sizeof(sbuf), "501 EPRT: %s resolved to multiple addresses\r\n", hostp); - return n > 0 ? write(src, sbuf, n) : n; + if (n < 0 || n >= sizeof(sbuf)) + n = 0; + if (n) + write(src, sbuf, n); + return n; } memcpy(&data6, res->ai_addr, res->ai_addrlen); @@ -942,13 +988,19 @@ eprtparamfail: if (epsvall) { n = snprintf(sbuf, sizeof(sbuf), "501 %s disallowed in EPSV ALL\r\n", cmd); - return n > 0 ? write(src, sbuf, n) : n; + if (n < 0 || n >= sizeof(sbuf)) + n = 0; + if (n) + write(src, sbuf, n); + return n; } /* transmit PASV */ n = snprintf(sbuf, sizeof(sbuf), "PASV\r\n"); - if (n > 0) - n = write(dst, sbuf, n); + if (n < 0 || n >= sizeof(sbuf)) + n = 0; + if (n) + write(dst, sbuf, n); *state = LPSV; passivemode = 0; /* to be set to 1 later */ return n; @@ -963,8 +1015,10 @@ eprtparamfail: wport4 = wport6 = port4 = port6 = -1; n = snprintf(sbuf, sizeof(sbuf), "PASV\r\n"); - if (n > 0) - n = write(dst, sbuf, n); + if (n < 0 || n >= sizeof(sbuf)) + n = 0; + if (n) + write(dst, sbuf, n); *state = EPSV; passivemode = 0; /* to be set to 1 later */ return n; @@ -975,120 +1029,21 @@ eprtparamfail: */ epsvall = 1; n = snprintf(sbuf, sizeof(sbuf), "200 EPSV ALL command successful.\r\n"); - return n > 0 ? write(src, sbuf, n) : n; -#ifdef FAITH4 - } else if (strcmp(cmd, "PORT") == 0 && param) { - /* - * PORT -> EPRT - */ - char host[NI_MAXHOST], serv[NI_MAXSERV]; - - nstate = PORT; - - close(wport4); - close(wport6); - close(port4); - close(port6); - wport4 = wport6 = port4 = port6 = -1; - - p = param; - n = sscanf(p, "%u,%u,%u,%u,%u,%u", - &ho[0], &ho[1], &ho[2], &ho[3], &po[0], &po[1]); - if (n != 6) { - n = snprintf(sbuf, sizeof(sbuf), - "501 illegal parameter to PORT\r\n"); - return n > 0 ? write(src, sbuf, n) : n; - } - - memset(&data6, 0, sizeof(data6)); - sin = (struct sockaddr_in *)&data6; - sin->sin_len = sizeof(*sin); - sin->sin_family = AF_INET; - sin->sin_addr.s_addr = htonl( - ((ho[0] & 0xff) << 24) | ((ho[1] & 0xff) << 16) | - ((ho[2] & 0xff) << 8) | (ho[3] & 0xff)); - sin->sin_port = htons(((po[0] & 0xff) << 8) | (po[1] & 0xff)); - - /* get ready for active data connection */ - n = sizeof(data4); - error = getsockname(dst, (struct sockaddr *)&data4, &n); - if (error == -1) { -portfail: - n = snprintf(sbuf, sizeof(sbuf), - "500 could not translate to EPRT\r\n"); - return n > 0 ? write(src, sbuf, n) : n; - } - if (((struct sockaddr *)&data4)->sa_family != AF_INET6) - goto portfail; - - ((struct sockaddr_in6 *)&data4)->sin6_port = 0; - sa = (struct sockaddr *)&data4; - wport4 = socket(sa->sa_family, SOCK_STREAM, 0); - if (wport4 == -1) - goto portfail; - error = bind(wport4, sa, sa->sa_len); - if (error == -1) { - close(wport4); - wport4 = -1; - goto portfail; - } - error = listen(wport4, 1); - if (error == -1) { - close(wport4); - wport4 = -1; - goto portfail; - } - - /* transmit EPRT */ - n = sizeof(data4); - error = getsockname(wport4, (struct sockaddr *)&data4, &n); - if (error == -1) { - close(wport4); - wport4 = -1; - goto portfail; - } - af = 2; - sa = (struct sockaddr *)&data4; - if (getnameinfo(sa, sa->sa_len, host, sizeof(host), - serv, sizeof(serv), NI_NUMERICHOST | NI_NUMERICSERV)) { - close(wport4); - wport4 = -1; - goto portfail; - } - n = snprintf(sbuf, sizeof(sbuf), "EPRT |%d|%s|%s|\r\n", af, host, serv); - if (n > 0) - n = write(dst, sbuf, n); - *state = nstate; - passivemode = 0; - return n; - } else if (strcmp(cmd, "PASV") == 0 && !param) { - /* - * PASV -> EPSV - */ - - nstate = PASV; - - close(wport4); - close(wport6); - close(port4); - close(port6); - wport4 = wport6 = port4 = port6 = -1; - - /* transmit EPSV */ - n = snprintf(sbuf, sizeof(sbuf), "EPSV\r\n"); - if (n > 0) - n = write(dst, sbuf, n); - *state = PASV; - passivemode = 0; /* to be set to 1 later */ + if (n < 0 || n >= sizeof(sbuf)) + n = 0; + if (n) + write(src, sbuf, n); return n; -#else /* FAITH4 */ } else if (strcmp(cmd, "PORT") == 0 || strcmp(cmd, "PASV") == 0) { /* * reject PORT/PASV */ n = snprintf(sbuf, sizeof(sbuf), "502 %s not implemented.\r\n", cmd); - return n > 0 ? write(src, sbuf, n) : n; -#endif /* FAITH4 */ + if (n < 0 || n >= sizeof(sbuf)) + n = 0; + if (n) + write(src, sbuf, n); + return n; } else if (passivemode && (strcmp(cmd, "STOR") == 0 || strcmp(cmd, "STOU") == 0 @@ -1103,8 +1058,10 @@ portfail: if (ftp_passiveconn() < 0) { n = snprintf(sbuf, sizeof(sbuf), "425 Cannot open data connetion\r\n"); - if (n > 0) - n = write(src, sbuf, n); + if (n < 0 || n >= sizeof(sbuf)) + n = 0; + if (n) + write(src, sbuf, n); } else { /* simply relay the command */ write(dst, rbuf, n); @@ -1115,7 +1072,8 @@ portfail: } else { /* simply relay it */ *state = NONE; - return write(dst, rbuf, n); + write(dst, rbuf, n); + return n; } bad: diff --git a/usr.sbin/faithd/prefix.c b/usr.sbin/faithd/prefix.c index 45140ca..138c948 100644 --- a/usr.sbin/faithd/prefix.c +++ b/usr.sbin/faithd/prefix.c @@ -1,4 +1,4 @@ -/* $KAME: prefix.c,v 1.9 2001/07/02 14:36:49 itojun Exp $ */ +/* $KAME: prefix.c,v 1.13 2003/09/02 22:50:17 itojun Exp $ */ /* $FreeBSD$ */ /* @@ -58,17 +58,16 @@ struct config *config_list = NULL; const int niflags = NI_NUMERICHOST; static int -prefix_set(s, prefix, slash) - const char *s; - struct prefix *prefix; - int slash; +prefix_set(const char *s, struct prefix *prefix, int slash) { - char *p, *q, *r; + char *p = NULL, *q, *r; struct addrinfo hints, *res = NULL; int max; char *a; p = strdup(s); + if (!p) + goto fail; q = strchr(p, '/'); if (q) { if (!slash) @@ -126,8 +125,7 @@ fail: } const char * -prefix_string(prefix) - const struct prefix *prefix; +prefix_string(const struct prefix *prefix) { static char buf[NI_MAXHOST + 20]; char hbuf[NI_MAXHOST]; @@ -140,9 +138,7 @@ prefix_string(prefix) } int -prefix_match(prefix, sa) - const struct prefix *prefix; - const struct sockaddr *sa; +prefix_match(const struct prefix *prefix, const struct sockaddr *sa) { struct sockaddr_storage a, b; char *pa, *pb; @@ -194,8 +190,7 @@ prefix_match(prefix, sa) * 3ffe::/16 permit 10.0.0.0/8 10.1.1.1 */ static struct config * -config_load1(line) - const char *line; +config_load1(const char *line) { struct config *conf; char buf[BUFSIZ]; @@ -268,8 +263,7 @@ fail: } int -config_load(configfile) - const char *configfile; +config_load(const char *configfile) { FILE *fp; char buf[BUFSIZ]; @@ -285,6 +279,7 @@ config_load(configfile) return -1; p = &sentinel; + sentinel.next = NULL; while (fgets(buf, sizeof(buf), fp) != NULL) { conf = config_load1(buf); if (conf) { @@ -300,8 +295,7 @@ config_load(configfile) #if 0 static void -config_show1(conf) - const struct config *conf; +config_show1(const struct config *conf) { const char *p; @@ -330,8 +324,7 @@ config_show() #endif const struct config * -config_match(sa1, sa2) - struct sockaddr *sa1, *sa2; +config_match(struct sockaddr *sa1, struct sockaddr *sa2) { static struct config conf; const struct config *p; diff --git a/usr.sbin/faithd/rsh.c b/usr.sbin/faithd/rsh.c deleted file mode 100644 index ab8e623e..0000000 --- a/usr.sbin/faithd/rsh.c +++ /dev/null @@ -1,212 +0,0 @@ -/* $KAME: rsh.c,v 1.7 2001/09/05 01:10:30 itojun Exp $ */ - -/* - * Copyright (C) 1997 and 1998 WIDE Project. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the project nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ - -#include <sys/param.h> -#include <sys/types.h> -#include <sys/socket.h> -#include <sys/ioctl.h> -#include <sys/time.h> - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <syslog.h> -#include <unistd.h> -#include <errno.h> - -#include <netinet/in.h> -#include <arpa/inet.h> -#include <netdb.h> - -#include "faithd.h" - -char rshbuf[MSS]; - -int s_ctl, s_ctl6, s_rcv, s_snd; -int half; - -void -rsh_relay(int s_src, int s_dst) -{ - ssize_t n; - fd_set readfds; - int error; - struct timeval tv; - - FD_ZERO(&readfds); - FD_SET(s_src, &readfds); - tv.tv_sec = FAITH_TIMEOUT; - tv.tv_usec = 0; - error = select(256, &readfds, NULL, NULL, &tv); - if (error == -1) - exit_failure("select %d: %s", s_src, strerror(errno)); - else if (error == 0) - exit_failure("connection timeout"); - - n = read(s_src, rshbuf, sizeof(rshbuf)); - if (rshbuf[0] != 0) { - rsh_dual_relay(s_src, s_dst); - /* NOTREACHED */ - } - write(s_dst, rshbuf, n); - tcp_relay(s_src, s_dst, "rsh"); - /* NOTREACHED */ -} - -static void -relay(int src, int dst) -{ - int error; - ssize_t n; - int atmark; - - error = ioctl(s_rcv, SIOCATMARK, &atmark); - if (error != -1 && atmark == 1) { - n = read(s_rcv, rshbuf, 1); - if (n == 1) - send(s_snd, rshbuf, 1, MSG_OOB); - return; - } - - n = read(s_rcv, rshbuf, sizeof(rshbuf)); - - switch (n) { - case -1: - exit_failure("%s", strerror(errno)); - case 0: - if (s_rcv == src) { - /* half close */ - shutdown(dst, 1); - half = YES; - break; - } - close(src); - close(dst); - close(s_ctl); - close(s_ctl6); - exit_success("terminating rsh/contorol connections"); - break; - default: - write(s_snd, rshbuf, n); - } -} - -void -rsh_dual_relay(int s_src, int s_dst) -{ - fd_set readfds; - int len, s_wld, error; - struct sockaddr_storage ctladdr6; - struct sockaddr_storage ctladdr; - int port6 = 0, lport, lport6; - char *p; - struct timeval tv; - struct sockaddr *sa; - - half = NO; - s_rcv = s_src; - s_snd = s_dst; - syslog(LOG_INFO, "starting rsh connection"); - - for (p = rshbuf; *p; p++) - port6 = port6 * 10 + *p - '0'; - - len = sizeof(ctladdr6); - getpeername(s_src, (struct sockaddr *)&ctladdr6, &len); - if (((struct sockaddr *)&ctladdr6)->sa_family == AF_INET6) - ((struct sockaddr_in6 *)&ctladdr6)->sin6_port = htons(port6); - else - ((struct sockaddr_in *)&ctladdr6)->sin_port = htons(port6); - - s_wld = rresvport(&lport); - if (s_wld == -1) goto bad; - error = listen(s_wld, 1); - if (error == -1) goto bad; - snprintf(rshbuf, sizeof(rshbuf), "%d", lport); - write(s_dst, rshbuf, strlen(rshbuf)+1); - - len = sizeof(ctladdr); - s_ctl = accept(s_wld, (struct sockaddr *)&ctladdr, &len); - if (s_ctl == -1) goto bad; - close(s_wld); - - sa = (struct sockaddr *)&ctladdr6; - s_ctl6 = rresvport_af(&lport6, sa->sa_family); - if (s_ctl6 == -1) goto bad; - error = connect(s_ctl6, sa, sa->sa_len); - if (error == -1) goto bad; - - syslog(LOG_INFO, "starting rsh control connection"); - - for (;;) { - FD_ZERO(&readfds); - if (half == NO) - FD_SET(s_src, &readfds); - FD_SET(s_dst, &readfds); - FD_SET(s_ctl, &readfds); - FD_SET(s_ctl6, &readfds); - tv.tv_sec = FAITH_TIMEOUT; - tv.tv_usec = 0; - - error = select(256, &readfds, NULL, NULL, &tv); - if (error == -1) - exit_failure("select 4 sockets: %s", strerror(errno)); - else if (error == 0) - exit_failure("connection timeout"); - - if (half == NO && FD_ISSET(s_src, &readfds)) { - s_rcv = s_src; - s_snd = s_dst; - relay(s_src, s_dst); - } - if (FD_ISSET(s_dst, &readfds)) { - s_rcv = s_dst; - s_snd = s_src; - relay(s_src, s_dst); - } - if (FD_ISSET(s_ctl, &readfds)) { - s_rcv = s_ctl; - s_snd = s_ctl6; - relay(s_src, s_dst); - } - if (FD_ISSET(s_ctl6, &readfds)) { - s_rcv = s_ctl6; - s_snd = s_ctl; - relay(s_src, s_dst); - } - } - /* NOTREACHED */ - - bad: - exit_failure("%s", strerror(errno)); -} diff --git a/usr.sbin/faithd/tcp.c b/usr.sbin/faithd/tcp.c index 68a2f51..714df9a 100644 --- a/usr.sbin/faithd/tcp.c +++ b/usr.sbin/faithd/tcp.c @@ -1,4 +1,4 @@ -/* $KAME: tcp.c,v 1.8 2001/11/21 07:40:22 itojun Exp $ */ +/* $KAME: tcp.c,v 1.13 2003/09/02 22:49:21 itojun Exp $ */ /* * Copyright (C) 1997 and 1998 WIDE Project. @@ -93,8 +93,9 @@ sig_child(int sig) pid_t pid; pid = wait3(&status, WNOHANG, (struct rusage *)0); - if (pid && WEXITSTATUS(status)) - syslog(LOG_WARNING, "child %d exit status 0x%x", pid, status); + if (pid > 0 && WEXITSTATUS(status)) + syslog(LOG_WARNING, "child %ld exit status 0x%x", + (long)pid, status); exit_success("terminate connection due to child termination"); } @@ -156,6 +157,8 @@ send_data(int s_rcv, int s_snd, const char *service, int direction) if (cc == -1) goto retry_or_err; oob_exists = 0; + if (s_rcv >= FD_SETSIZE) + exit_failure("descriptor too big"); FD_SET(s_rcv, &exceptfds); } @@ -174,12 +177,18 @@ send_data(int s_rcv, int s_snd, const char *service, int direction) } #endif /* DEBUG */ tblen = 0; tboff = 0; + if (s_snd >= FD_SETSIZE) + exit_failure("descriptor too big"); FD_CLR(s_snd, &writefds); + if (s_rcv >= FD_SETSIZE) + exit_failure("descriptor too big"); FD_SET(s_rcv, &readfds); return; retry_or_err: if (errno != EAGAIN) exit_failure("writing relay data failed: %s", strerror(errno)); + if (s_snd >= FD_SETSIZE) + exit_failure("descriptor too big"); FD_SET(s_snd, &writefds); } @@ -195,6 +204,8 @@ relay(int s_rcv, int s_snd, const char *service, int direction) FD_ZERO(&exceptfds); fcntl(s_snd, F_SETFD, O_NONBLOCK); oreadfds = readfds; owritefds = writefds; oexceptfds = exceptfds; + if (s_rcv >= FD_SETSIZE) + exit_failure("descriptor too big"); FD_SET(s_rcv, &readfds); FD_SET(s_rcv, &exceptfds); oob_exists = 0; @@ -229,7 +240,11 @@ relay(int s_rcv, int s_snd, const char *service, int direction) oob_read_retry: cc = read(s_rcv, atmark_buf, 1); if (cc == 1) { + if (s_rcv >= FD_SETSIZE) + exit_failure("descriptor too big"); FD_CLR(s_rcv, &exceptfds); + if (s_snd >= FD_SETSIZE) + exit_failure("descriptor too big"); FD_SET(s_snd, &writefds); oob_exists = 1; } else if (cc == -1) { @@ -262,7 +277,11 @@ relay(int s_rcv, int s_snd, const char *service, int direction) exit_success("terminating %s relay", service); /* NOTREACHED */ default: + if (s_rcv >= FD_SETSIZE) + exit_failure("descriptor too big"); FD_CLR(s_rcv, &readfds); + if (s_snd >= FD_SETSIZE) + exit_failure("descriptor too big"); FD_SET(s_snd, &writefds); break; } diff --git a/usr.sbin/faithd/test/faithd.rb b/usr.sbin/faithd/test/faithd.rb index 683b504..682f540 100644 --- a/usr.sbin/faithd/test/faithd.rb +++ b/usr.sbin/faithd/test/faithd.rb @@ -3,7 +3,7 @@ # highly experimental (not working right at all) and very limited # functionality. # -# $Id: faithd.rb,v 1.1.1.1 1999/08/08 23:29:31 itojun Exp $ +# $Id: faithd.rb,v 1.1.2.4 1999/05/10 17:06:30 itojun Exp $ # $FreeBSD$ require "socket" |