diff options
author | Jun-ichiro itojun Hagino <itojun@cvs.openbsd.org> | 2001-02-15 17:37:34 +0000 |
---|---|---|
committer | Jun-ichiro itojun Hagino <itojun@cvs.openbsd.org> | 2001-02-15 17:37:34 +0000 |
commit | bd74ca448b83994d40bb8b97d267863785e098a6 (patch) | |
tree | 76b1d97cd8ff19f539ac406c7090ffc2d9ed2b5c /usr.sbin/faithd | |
parent | e67e266e4982c344ac308ec37afc140fdfebe986 (diff) |
pull latest KAME faithd. access control is possible by /etc/faithd.conf.
req'ed by todd
Diffstat (limited to 'usr.sbin/faithd')
-rw-r--r-- | usr.sbin/faithd/Makefile | 4 | ||||
-rw-r--r-- | usr.sbin/faithd/faithd.8 | 120 | ||||
-rw-r--r-- | usr.sbin/faithd/faithd.c | 108 | ||||
-rw-r--r-- | usr.sbin/faithd/prefix.c | 360 | ||||
-rw-r--r-- | usr.sbin/faithd/prefix.h | 52 | ||||
-rw-r--r-- | usr.sbin/faithd/rsh.c | 8 |
6 files changed, 610 insertions, 42 deletions
diff --git a/usr.sbin/faithd/Makefile b/usr.sbin/faithd/Makefile index da285983e0f..b36a0d2fc26 100644 --- a/usr.sbin/faithd/Makefile +++ b/usr.sbin/faithd/Makefile @@ -1,7 +1,7 @@ -# $OpenBSD: Makefile,v 1.1 1999/12/20 16:32:53 itojun Exp $ +# $OpenBSD: Makefile,v 1.2 2001/02/15 17:37:33 itojun Exp $ PROG= faithd -SRCS= faithd.c tcp.c ftp.c rsh.c +SRCS= faithd.c tcp.c ftp.c rsh.c prefix.c MAN= faithd.8 diff --git a/usr.sbin/faithd/faithd.8 b/usr.sbin/faithd/faithd.8 index 79b929c0bdc..017733ed062 100644 --- a/usr.sbin/faithd/faithd.8 +++ b/usr.sbin/faithd/faithd.8 @@ -1,5 +1,5 @@ -.\" $OpenBSD: faithd.8,v 1.9 2001/02/15 16:35:16 todd Exp $ -.\" $KAME: faithd.8,v 1.14 2000/09/12 05:20:35 itojun Exp $ +.\" $OpenBSD: faithd.8,v 1.10 2001/02/15 17:37:33 itojun Exp $ +.\" $KAME: faithd.8,v 1.20 2001/01/22 02:23:40 itojun Exp $ .\" .\" Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. .\" All rights reserved. @@ -37,6 +37,7 @@ .Sh SYNOPSIS .Nm .Op Fl dp +.Op Fl f Ar configfile .Ar service .Op Ar serverpath Op Ar serverargs .Nm "" @@ -97,6 +98,24 @@ address prefix, by using and .Xr sysctl 8 commands. +.Pp +.Nm +needs a special name-to-address translation logic, so that +hostnames gets resolved into special +.Tn IPv6 +address prefix. +For small-scale installation, use +.Xr hosts 5 . +For large-scale installation, it is useful to have +a DNS server with special address translation support. +An implementation called +.Nm totd +is available +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 @@ -138,22 +157,23 @@ You can also specify .Ar serverargs for the arguments for the local daemon. .Pp -If -.Fl d -is given, debugging information will be generated using +The following options are available: +.Bl -tag -width indent +.It Fl d +Debugging information will be generated using .Xr syslog 3 . -If -.Fl p -is given, -.Nm -will use privileged TCP port number as source port, +.It Fl f Ar configfile +Specify a configuration file for access control. +See below. +.It Fl p +Use privileged TCP port number as source port, for IPv4 TCP connection toward final destination. For relaying .Xr ftp 1 and .Xr rlogin 1 , -.Fl p -is not necessary as special program code is supplied. +this flag is not necessary as special program code is supplied. +.El .Pp .Nm will relay both normal and out-of-band TCP data. @@ -182,6 +202,52 @@ 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 .Pq should this be configurable? . +.Ss Access control +To prevent malicious accesses, +.Nm +implements a simple address-based access control. +With +.Pa /etc/faithd.conf +.Po +or +.Ar configfile +specified by +.Fl f +.Pc , +.Nm +will avoid relaying unwanted traffic. +The +.Pa faithd.conf +contains directives with the following format: +.Bl -bullet +.It +.Xo +.Ic Ar src/slen Li deny Ar dst/dlen +.Xc +.Pp +If the source address of a query matches +.Ar src/slen , +and the translated destination address matches +.Ar dst/dlen , +deny the connection. +.It +.Xo +.Ic Ar src/slen Li permit Ar dst/dlen +.Xc +.Pp +If the source address of a query matches +.Ar src/slen , +and the translated destination address matches +.Ar dst/dlen , +permit the connection. +.El +.Pp +The directives are evaluated in sequence, +and the first matching entry will be effective. +.\".Pp +.\"With inetd mode, +.\"traffic may be filtered by using access control functionality in +.\".Xr inetd 8 . .Sh EXAMPLES Before invoking .Nm Ns , @@ -195,6 +261,7 @@ interface has to be configured properly. # route add -inet6 3ffe:501:4819:ffff:: -prefixlen 96 ::1 # route change -inet6 3ffe:501:4819:ffff:: -prefixlen 96 -ifp faith0 .Ed +.Pp .\".Ss Daemon mode samples To translate .Li telnet @@ -217,7 +284,7 @@ use the following command line: .Pp If you would like to pass extra arguments to the local daemon: .Bd -literal -offset -# faithd ftpd /usr/libexec/ftpd ftpd -l +# faithd ftp /usr/libexec/ftpd ftpd -l .Ed .Pp Here are some other examples. @@ -231,9 +298,24 @@ to translate rsh/rlogin services. .Ed .Pp However, you should be careful when translating rlogin or rsh -connections. See +connections. +See .Sx SECURITY NOTICE for more details. +.Ss Access control samples +The following illustrates a simple +.Pa faithd.conf +setting. +.Bd -literal -offset +# permit anyone from 3ffe:501:ffff::/48 to use the translator, +# to connect to the following IPv4 destinations: +# - any location except 10.0.0.0/8 and 127.0.0.0/8. +# Permit no other connections. +# +3ffe:501:ffff::/48 deny 10.0.0.0/8 +3ffe:501:ffff::/48 deny 127.0.0.0/8 +3ffe:501:ffff::/48 permit 0.0.0.0/0 +.Ed .Sh RETURN VALUES .Nm exits with @@ -262,10 +344,14 @@ and other IP-address based authentication, for connections relayed by .Nm .Pq and any other TCP relaying services . .Pp +Administrators are advised to limit accesses to +.Nm +using +.Pa faithd.conf , +or by using IPv6 packet filters. +It is to protect .Nm -itself does not implement access controls, as -it intends to implement transparent TCP relay services. -Administrators are advised to filter packets based on IPv6 address. +service from malicious parties and avoid theft of service/bandwidth. IPv6 destination address can be limited by carefully configuring routing entries that points to .Xr faith 4 , diff --git a/usr.sbin/faithd/faithd.c b/usr.sbin/faithd/faithd.c index bab7391eaae..223bc3ef408 100644 --- a/usr.sbin/faithd/faithd.c +++ b/usr.sbin/faithd/faithd.c @@ -1,5 +1,5 @@ -/* $OpenBSD: faithd.c,v 1.9 2000/10/06 02:46:58 itojun Exp $ */ -/* $KAME: faithd.c,v 1.31 2000/10/05 22:20:37 itojun Exp $ */ +/* $OpenBSD: faithd.c,v 1.10 2001/02/15 17:37:33 itojun Exp $ */ +/* $KAME: faithd.c,v 1.35 2001/02/10 05:24:52 itojun Exp $ */ /* * Copyright (C) 1997 and 1998 WIDE Project. @@ -85,6 +85,7 @@ #endif #include "faithd.h" +#include "prefix.h" char *serverpath = NULL; char *serverarg[MAXARGV + 1]; @@ -103,6 +104,7 @@ static int sockfd = 0; int dflag = 0; static int pflag = 0; static int inetd = 0; +static char *configfile = NULL; int main __P((int, char **)); #if 0 @@ -167,6 +169,11 @@ inetd_main(int argc, char **argv) const int on = 1; char sbuf[NI_MAXSERV], snum[NI_MAXSERV]; + if (config_load(configfile) < 0 && configfile) { + exit_failure("could not load config file"); + /*NOTREACHED*/ + } + if (strrchr(argv[0], '/') == NULL) snprintf(path, sizeof(path), "%s/%s", DEFAULT_DIR, argv[0]); else @@ -183,11 +190,15 @@ inetd_main(int argc, char **argv) #endif melen = sizeof(me); - if (getsockname(STDIN_FILENO, (struct sockaddr *)&me, &melen) < 0) + if (getsockname(STDIN_FILENO, (struct sockaddr *)&me, &melen) < 0) { exit_failure("getsockname: %s", ERRSTR); + /*NOTREACHED*/ + } fromlen = sizeof(from); - if (getpeername(STDIN_FILENO, (struct sockaddr *)&from, &fromlen) < 0) + if (getpeername(STDIN_FILENO, (struct sockaddr *)&from, &fromlen) < 0) { exit_failure("getpeername: %s", ERRSTR); + /*NOTREACHED*/ + } if (getnameinfo((struct sockaddr *)&me, melen, NULL, 0, sbuf, sizeof(sbuf), NI_NUMERICHOST) == 0) service = sbuf; @@ -201,8 +212,10 @@ inetd_main(int argc, char **argv) snprintf(procname, sizeof(procname), "accepting port %s", snum); openlog(logname, LOG_PID | LOG_NOWAIT, LOG_DAEMON); - if (argc >= MAXARGV) + if (argc >= MAXARGV) { exit_failure("too many arguments"); + /*NOTREACHED*/ + } serverarg[0] = serverpath = path; for (i = 1; i < argc; i++) serverarg[i] = argv[i]; @@ -210,8 +223,10 @@ inetd_main(int argc, char **argv) error = setsockopt(STDIN_FILENO, SOL_SOCKET, SO_OOBINLINE, &on, sizeof(on)); - if (error < 0) + if (error < 0) { exit_failure("setsockopt(SO_OOBINLINE): %s", ERRSTR); + /*NOTREACHED*/ + } play_child(STDIN_FILENO, (struct sockaddr *)&from); exit_failure("should not reach here"); @@ -230,11 +245,14 @@ daemon_main(int argc, char **argv) char *ns; #endif /* FAITH_NS */ - while ((c = getopt(argc, argv, "dp46")) != -1) { + while ((c = getopt(argc, argv, "df:p46")) != -1) { switch (c) { case 'd': dflag++; break; + case 'f': + configfile = optarg; + break; case 'p': pflag++; break; @@ -254,6 +272,11 @@ daemon_main(int argc, char **argv) argc -= optind; argv += optind; + if (config_load(configfile) < 0 && configfile) { + exit_failure("could not load config file"); + /*NOTREACHED*/ + } + #ifdef FAITH_NS if ((ns = getenv(FAITH_NS)) != NULL) { struct sockaddr_storage ss; @@ -416,8 +439,10 @@ again: len = sizeof(srcaddr); s_src = accept(s_wld, (struct sockaddr *)&srcaddr, &len); - if (s_src == -1) + if (s_src == -1) { exit_failure("socket: %s", ERRSTR); + /*NOTREACHED*/ + } child_pid = fork(); @@ -428,6 +453,7 @@ again: openlog(logname, LOG_PID | LOG_NOWAIT, LOG_DAEMON); play_child(s_src, (struct sockaddr *)&srcaddr); exit_failure("should never reach here"); + /*NOTREACHED*/ } else { /* parent process */ close(s_src); @@ -450,6 +476,7 @@ play_child(int s_src, struct sockaddr *srcaddr) int s_dst, error, hport, nresvport, on = 1; struct timeval tv; struct sockaddr *sa4; + const struct config *conf; tv.tv_sec = 1; tv.tv_usec = 0; @@ -459,8 +486,10 @@ play_child(int s_src, struct sockaddr *srcaddr) syslog(LOG_INFO, "accepted a client from %s", src); error = getsockname(s_src, (struct sockaddr *)&dstaddr6, &len); - if (error == -1) + if (error == -1) { exit_failure("getsockname: %s", ERRSTR); + /*NOTREACHED*/ + } getnameinfo((struct sockaddr *)&dstaddr6, len, dst6, sizeof(dst6), NULL, 0, NI_NUMERICHOST); @@ -497,6 +526,7 @@ play_child(int s_src, struct sockaddr *srcaddr) (struct sockaddr_in *)&dstaddr4)) { close(s_src); exit_failure("map6to4 failed"); + /*NOTREACHED*/ } syslog(LOG_INFO, "translating from v6 to v4"); break; @@ -506,6 +536,7 @@ play_child(int s_src, struct sockaddr *srcaddr) (struct sockaddr_in6 *)&dstaddr4)) { close(s_src); exit_failure("map4to6 failed"); + /*NOTREACHED*/ } syslog(LOG_INFO, "translating from v4 to v6"); break; @@ -519,6 +550,15 @@ play_child(int s_src, struct sockaddr *srcaddr) sa4 = (struct sockaddr *)&dstaddr4; getnameinfo(sa4, sa4->sa_len, dst4, sizeof(dst4), NULL, 0, NI_NUMERICHOST); + + conf = config_match(srcaddr, sa4); + if (!conf || !conf->permit) { + close(s_src); + exit_failure("translation to %s not permitted for %s", dst4, + prefix_string(&conf->match)); + /*NOTREACHED*/ + } + syslog(LOG_INFO, "the translator is connecting to %s", dst4); setproctitle("port %s, %s -> %s", service, src, dst4); @@ -540,31 +580,55 @@ play_child(int s_src, struct sockaddr *srcaddr) s_dst = socket(sa4->sa_family, SOCK_STREAM, 0); break; } - if (s_dst == -1) + if (s_dst < 0) { exit_failure("socket: %s", ERRSTR); + /*NOTREACHED*/ + } + + if (conf->src.a.ss_family) { + if (bind(s_dst, (struct sockaddr *)&conf->src.a, + conf->src.a.ss_len) < 0) { + exit_failure("bind: %s", ERRSTR); + /*NOTREACHED*/ + } + } error = setsockopt(s_dst, SOL_SOCKET, SO_OOBINLINE, &on, sizeof(on)); - if (error == -1) + if (error < 0) { exit_failure("setsockopt(SO_OOBINLINE): %s", ERRSTR); + /*NOTREACHED*/ + } error = setsockopt(s_src, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)); - if (error == -1) + if (error < 0) { exit_failure("setsockopt(SO_SNDTIMEO): %s", ERRSTR); + /*NOTREACHED*/ + } error = setsockopt(s_dst, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)); - if (error == -1) + if (error < 0) { exit_failure("setsockopt(SO_SNDTIMEO): %s", ERRSTR); + /*NOTREACHED*/ + } error = connect(s_dst, sa4, sa4->sa_len); - if (error == -1) + if (error < 0) { exit_failure("connect: %s", ERRSTR); + /*NOTREACHED*/ + } switch (hport) { 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; @@ -590,8 +654,10 @@ faith_prefix(struct sockaddr *dst) mib[2] = IPPROTO_IPV6; mib[3] = IPV6CTL_FAITH_PREFIX; size = sizeof(struct in6_addr); - if (sysctl(mib, 4, &faith_prefix, &size, NULL, 0) < 0) + if (sysctl(mib, 4, &faith_prefix, &size, NULL, 0) < 0) { exit_failure("sysctl: %s", ERRSTR); + /*NOTREACHED*/ + } if (memcmp(dst, &faith_prefix, sizeof(struct in6_addr) - sizeof(struct in_addr) == 0) { @@ -721,11 +787,15 @@ start_daemon(void) if (daemon(0, 0) == -1) exit_stderr("daemon: %s", ERRSTR); - if (signal(SIGCHLD, sig_child) == SIG_ERR) + if (signal(SIGCHLD, sig_child) == SIG_ERR) { exit_failure("signal CHLD: %s", ERRSTR); + /*NOTREACHED*/ + } - if (signal(SIGTERM, sig_terminate) == SIG_ERR) + if (signal(SIGTERM, sig_terminate) == SIG_ERR) { exit_failure("signal TERM: %s", ERRSTR); + /*NOTREACHED*/ + } } static void @@ -737,7 +807,7 @@ exit_stderr(const char *fmt, ...) va_start(ap, fmt); vsnprintf(buf, sizeof(buf), fmt, ap); va_end(ap); - fprintf(stderr, "%s", buf); + fprintf(stderr, "%s\n", buf); exit(EXIT_FAILURE); } @@ -986,7 +1056,7 @@ update_myaddrs() static void usage() { - fprintf(stderr, "usage: %s [-dp] service [serverpath [serverargs]]\n", + fprintf(stderr, "usage: %s [-dp] [-f conf] service [serverpath [serverargs]]\n", faithdname); exit(0); } diff --git a/usr.sbin/faithd/prefix.c b/usr.sbin/faithd/prefix.c new file mode 100644 index 00000000000..4c124f54845 --- /dev/null +++ b/usr.sbin/faithd/prefix.c @@ -0,0 +1,360 @@ +/* $OpenBSD: prefix.c,v 1.1 2001/02/15 17:37:33 itojun Exp $ */ +/* $KAME: prefix.c,v 1.8 2000/11/24 06:16:56 itojun Exp $ */ + +/* + * Copyright (C) 2000 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. + */ + +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <stdio.h> +#include <netdb.h> +#include <string.h> +#include <stddef.h> +#include <stdlib.h> +#include <limits.h> + +#ifndef offsetof +#define offsetof(type, member) ((size_t)(u_long)(&((type *)0)->member)) +#endif + +#include "faithd.h" +#include "prefix.h" + +static int prefix_set __P((const char *, struct prefix *, int)); +static struct config *config_load1 __P((const char *)); +#if 0 +static void config_show1 __P((const struct config *)); +static void config_show __P((void)); +#endif + +struct config *config_list = NULL; +#ifdef NI_WITHSCOPEID +const int niflags = NI_NUMERICHOST | NI_WITHSCOPEID; +#else +const int niflags = NI_NUMERICHOST; +#endif + +static int +prefix_set(s, prefix, slash) + const char *s; + struct prefix *prefix; + int slash; +{ + char *p, *q, *r; + struct addrinfo hints, *res = NULL; + int max; + char *a; + + p = strdup(s); + q = strchr(p, '/'); + if (q) { + if (!slash) + goto fail; + *q++ = '\0'; + } + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = PF_UNSPEC; + hints.ai_socktype = SOCK_DGRAM; /*dummy*/ + hints.ai_flags = AI_NUMERICHOST; + if (getaddrinfo(p, "0", &hints, &res)) + goto fail; + if (res->ai_next || res->ai_addrlen > sizeof(prefix->a)) + goto fail; + memcpy(&prefix->a, res->ai_addr, res->ai_addrlen); + + switch (prefix->a.ss_family) { + case AF_INET: + max = 32; + a = (char *)&((struct sockaddr_in *)&prefix->a)->sin_addr; + break; + case AF_INET6: + max = 128; + a = (char *)&((struct sockaddr_in6 *)&prefix->a)->sin6_addr; + break; + default: + a = NULL; + max = -1; + break; + } + + if (q) { + r = NULL; + prefix->l = (int)strtoul(q, &r, 10); + if (!*q || *r) + goto fail; + if (prefix->l < 0 || prefix->l > max) + goto fail; + } else + prefix->l = max; + + if (p) + free(p); + if (res) + freeaddrinfo(res); + return 0; + +fail: + if (p) + free(p); + if (res) + freeaddrinfo(res); + return -1; +} + +const char * +prefix_string(prefix) + const struct prefix *prefix; +{ + static char buf[NI_MAXHOST + 20]; + char hbuf[NI_MAXHOST]; + + if (getnameinfo((struct sockaddr *)&prefix->a, prefix->a.ss_len, hbuf, + sizeof(hbuf), NULL, 0, niflags)) + return NULL; + snprintf(buf, sizeof(buf), "%s/%d", hbuf, prefix->l); + return buf; +} + +int +prefix_match(prefix, sa) + const struct prefix *prefix; + const struct sockaddr *sa; +{ + struct sockaddr_storage a, b; + char *pa, *pb; + int off, l; + + if (prefix->a.ss_family != sa->sa_family || + prefix->a.ss_len != sa->sa_len) + return 0; + + if (prefix->a.ss_len > sizeof(a) || sa->sa_len > sizeof(b)) + return 0; + + switch (prefix->a.ss_family) { + case AF_INET: + off = offsetof(struct sockaddr_in, sin_addr); + break; + case AF_INET6: + off = offsetof(struct sockaddr_in6, sin6_addr); + break; + default: + if (memcmp(&prefix->a, sa, prefix->a.ss_len) != 0) + return 0; + else + return 1; + } + + memcpy(&a, &prefix->a, prefix->a.ss_len); + memcpy(&b, sa, sa->sa_len); + l = prefix->l / 8 + (prefix->l % 8 ? 1 : 0); + + /* overrun check */ + if (off + l > a.ss_len) + return 0; + + pa = ((char *)&a) + off; + pb = ((char *)&b) + off; + if (prefix->l % 8) { + pa[prefix->l / 8] &= 0xff00 >> (prefix->l % 8); + pb[prefix->l / 8] &= 0xff00 >> (prefix->l % 8); + } + if (memcmp(pa, pb, l) != 0) + return 0; + else + return 1; +} + +/* + * prefix/prefixlen permit/deny prefix/prefixlen [srcaddr] + * 3ffe::/16 permit 10.0.0.0/8 10.1.1.1 + */ +static struct config * +config_load1(line) + const char *line; +{ + struct config *conf; + char buf[BUFSIZ]; + char *p; + char *token[4]; + int i; + + if (strlen(line) + 1 > sizeof(buf)) + return NULL; + strlcpy(buf, line, sizeof(buf)); + + p = strchr(buf, '\n'); + if (!p) + return NULL; + *p = '\0'; + p = strchr(buf, '#'); + if (p) + *p = '\0'; + if (strlen(buf) == 0) + return NULL; + + p = buf; + memset(token, 0, sizeof(token)); + for (i = 0; i < sizeof(token) / sizeof(token[0]); i++) { + token[i] = strtok(p, "\t "); + p = NULL; + if (token[i] == NULL) + break; + } + /* extra tokens? */ + if (strtok(p, "\t ") != NULL) + return NULL; + /* insufficient tokens */ + switch (i) { + case 3: + case 4: + break; + default: + return NULL; + } + + conf = (struct config *)malloc(sizeof(*conf)); + if (conf == NULL) + return NULL; + memset(conf, 0, sizeof(*conf)); + + if (strcasecmp(token[1], "permit") == 0) + conf->permit = 1; + else if (strcasecmp(token[1], "deny") == 0) + conf->permit = 0; + else { + /* invalid keyword is considered as "deny" */ + conf->permit = 0; + } + + if (prefix_set(token[0], &conf->match, 1) < 0) + goto fail; + if (prefix_set(token[2], &conf->dest, 1) < 0) + goto fail; + if (token[3]) { + if (prefix_set(token[3], &conf->src, 0) < 0) + goto fail; + } + + return conf; + +fail: + free(conf); + return NULL; +} + +int +config_load(configfile) + const char *configfile; +{ + FILE *fp; + char buf[BUFSIZ]; + struct config *conf, *p; + struct config sentinel; + + config_list = NULL; + + if (!configfile) + configfile = _PATH_PREFIX_CONF; + fp = fopen(configfile, "r"); + if (fp == NULL) + return -1; + + p = &sentinel; + while (fgets(buf, sizeof(buf), fp) != NULL) { + conf = config_load1(buf); + if (conf) { + p->next = conf; + p = p->next; + } + } + config_list = sentinel.next; + + fclose(fp); + return 0; +} + +#if 0 +static void +config_show1(conf) + const struct config *conf; +{ + const char *p; + + p = prefix_string(&conf->match); + printf("%s", p ? p : "?"); + + if (conf->permit) + printf(" permit"); + else + printf(" deny"); + + p = prefix_string(&conf->dest); + printf(" %s", p ? p : "?"); + + printf("\n"); +} + +static void +config_show() +{ + struct config *conf; + + for (conf = config_list; conf; conf = conf->next) + config_show1(conf); +} +#endif + +const struct config * +config_match(sa1, sa2) + struct sockaddr *sa1, *sa2; +{ + static struct config conf; + const struct config *p; + + if (sa1->sa_len > sizeof(conf.match.a) || + sa2->sa_len > sizeof(conf.dest.a)) + return NULL; + + memset(&conf, 0, sizeof(conf)); + if (!config_list) { + conf.permit = 1; + memcpy(&conf.match.a, sa1, sa1->sa_len); + memcpy(&conf.dest.a, sa2, sa2->sa_len); + return &conf; + } + + for (p = config_list; p; p = p->next) + if (prefix_match(&p->match, sa1) && prefix_match(&p->dest, sa2)) + return p; + + return NULL; +} diff --git a/usr.sbin/faithd/prefix.h b/usr.sbin/faithd/prefix.h new file mode 100644 index 00000000000..971a4347f9a --- /dev/null +++ b/usr.sbin/faithd/prefix.h @@ -0,0 +1,52 @@ +/* $OpenBSD: prefix.h,v 1.1 2001/02/15 17:37:33 itojun Exp $ */ +/* $KAME: prefix.h,v 1.3 2000/11/19 11:45:38 itojun Exp $ */ + +/* + * Copyright (C) 2000 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. + */ + +struct prefix { + struct sockaddr_storage a; + int l; +}; + +struct config { + struct config *next; + + int permit; + struct prefix match; + struct prefix dest; + struct prefix src; /* src to use for outgoing connection */ +}; + +#define _PATH_PREFIX_CONF "/etc/faithd.conf" + +extern const char *prefix_string __P((const struct prefix *)); +extern int prefix_match __P((const struct prefix *, const struct sockaddr *)); +extern int config_load __P((const char *)); +extern const struct config *config_match __P((struct sockaddr *, struct sockaddr *)); diff --git a/usr.sbin/faithd/rsh.c b/usr.sbin/faithd/rsh.c index 3603e2d5577..d7cdc1282e2 100644 --- a/usr.sbin/faithd/rsh.c +++ b/usr.sbin/faithd/rsh.c @@ -1,5 +1,5 @@ -/* $OpenBSD: rsh.c,v 1.3 2000/05/31 03:09:22 itojun Exp $ */ -/* $KAME: rsh.c,v 1.3 2000/05/31 03:06:07 itojun Exp $ */ +/* $OpenBSD: rsh.c,v 1.4 2001/02/15 17:37:33 itojun Exp $ */ +/* $KAME: rsh.c,v 1.5 2001/02/15 17:28:04 itojun Exp $ */ /* * Copyright (C) 1997 and 1998 WIDE Project. @@ -70,7 +70,7 @@ rsh_relay(int s_src, int s_dst) if (error == -1) exit_failure("select %d: %s", s_src, ERRSTR); else if (error == 0) - exit_failure("connecion timeout"); + exit_failure("connection timeout"); n = read(s_src, rshbuf, sizeof(rshbuf)); if (rshbuf[0] != 0) { @@ -181,7 +181,7 @@ rsh_dual_relay(int s_src, int s_dst) if (error == -1) exit_failure("select 4 sockets: %s", ERRSTR); else if (error == 0) - exit_failure("connecion timeout"); + exit_failure("connection timeout"); if (half == NO && FD_ISSET(s_src, &readfds)) { s_rcv = s_src; |