diff options
Diffstat (limited to 'contrib/netbsd-tests/fs/nfs/nfsservice/rpcbind/security.c')
-rw-r--r-- | contrib/netbsd-tests/fs/nfs/nfsservice/rpcbind/security.c | 282 |
1 files changed, 282 insertions, 0 deletions
diff --git a/contrib/netbsd-tests/fs/nfs/nfsservice/rpcbind/security.c b/contrib/netbsd-tests/fs/nfs/nfsservice/rpcbind/security.c new file mode 100644 index 0000000..755c0d3 --- /dev/null +++ b/contrib/netbsd-tests/fs/nfs/nfsservice/rpcbind/security.c @@ -0,0 +1,282 @@ +/* $NetBSD: security.c,v 1.1 2010/07/26 15:53:01 pooka Exp $ */ + +#include <sys/types.h> +#include <sys/time.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <rpc/rpc.h> +#include <rpc/rpcb_prot.h> +#include <rpc/pmap_prot.h> +#include <err.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <util.h> +#include <syslog.h> +#include <netdb.h> + +/* + * XXX for special case checks in check_callit. + */ +#include <rpcsvc/mount.h> +#include <rpcsvc/rquota.h> +#include <rpcsvc/nfs_prot.h> +#include <rpcsvc/yp.h> +#include <rpcsvc/ypclnt.h> +#include <rpcsvc/yppasswd.h> + +#include "rpcbind.h" + +#ifdef LIBWRAP +# include <tcpd.h> +#ifndef LIBWRAP_ALLOW_FACILITY +# define LIBWRAP_ALLOW_FACILITY LOG_AUTH +#endif +#ifndef LIBWRAP_ALLOW_SEVERITY +# define LIBWRAP_ALLOW_SEVERITY LOG_INFO +#endif +#ifndef LIBWRAP_DENY_FACILITY +# define LIBWRAP_DENY_FACILITY LOG_AUTH +#endif +#ifndef LIBWRAP_DENY_SEVERITY +# define LIBWRAP_DENY_SEVERITY LOG_WARNING +#endif +int allow_severity = LIBWRAP_ALLOW_FACILITY|LIBWRAP_ALLOW_SEVERITY; +int deny_severity = LIBWRAP_DENY_FACILITY|LIBWRAP_DENY_SEVERITY; +#endif + +#ifndef PORTMAP_LOG_FACILITY +# define PORTMAP_LOG_FACILITY LOG_AUTH +#endif +#ifndef PORTMAP_LOG_SEVERITY +# define PORTMAP_LOG_SEVERITY LOG_INFO +#endif +int log_severity = PORTMAP_LOG_FACILITY|PORTMAP_LOG_SEVERITY; + +extern int verboselog; + +int +check_access(SVCXPRT *xprt, rpcproc_t proc, void *args, int rpcbvers) +{ + struct netbuf *caller = svc_getrpccaller(xprt); + struct sockaddr *addr = (struct sockaddr *)caller->buf; +#ifdef LIBWRAP + struct request_info req; +#endif + rpcprog_t prog = 0; + rpcb *rpcbp; + struct pmap *pmap; + + /* + * The older PMAP_* equivalents have the same numbers, so + * they are accounted for here as well. + */ + switch (proc) { + case RPCBPROC_GETADDR: + case RPCBPROC_SET: + case RPCBPROC_UNSET: + if (rpcbvers > PMAPVERS) { + rpcbp = (rpcb *)args; + prog = rpcbp->r_prog; + } else { + pmap = (struct pmap *)args; + prog = pmap->pm_prog; + } + if (proc == RPCBPROC_GETADDR) + break; + if (!insecure && !is_loopback(caller)) { + if (verboselog) + logit(log_severity, addr, proc, prog, + " declined (non-loopback sender)"); + return 0; + } + break; + case RPCBPROC_CALLIT: + case RPCBPROC_INDIRECT: + case RPCBPROC_DUMP: + case RPCBPROC_GETTIME: + case RPCBPROC_UADDR2TADDR: + case RPCBPROC_TADDR2UADDR: + case RPCBPROC_GETVERSADDR: + case RPCBPROC_GETADDRLIST: + case RPCBPROC_GETSTAT: + default: + break; + } + +#ifdef LIBWRAP + if (addr->sa_family == AF_LOCAL) + return 1; + request_init(&req, RQ_DAEMON, "rpcbind", RQ_CLIENT_SIN, addr, 0); + sock_methods(&req); + if(!hosts_access(&req)) { + logit(deny_severity, addr, proc, prog, ": request from unauthorized host"); + return 0; + } +#endif + if (verboselog) + logit(log_severity, addr, proc, prog, ""); + return 1; +} + +int +is_loopback(struct netbuf *nbuf) +{ + struct sockaddr *addr = (struct sockaddr *)nbuf->buf; + struct sockaddr_in *sin; +#ifdef INET6 + struct sockaddr_in6 *sin6; +#endif + + switch (addr->sa_family) { + case AF_INET: + if (!oldstyle_local) + return 0; + sin = (struct sockaddr_in *)addr; + return ((sin->sin_addr.s_addr == htonl(INADDR_LOOPBACK)) && + (ntohs(sin->sin_port) < IPPORT_RESERVED)); +#ifdef INET6 + case AF_INET6: + if (!oldstyle_local) + return 0; + sin6 = (struct sockaddr_in6 *)addr; + return (IN6_IS_ADDR_LOOPBACK(&sin6->sin6_addr) && + (ntohs(sin6->sin6_port) < IPV6PORT_RESERVED)); +#endif + case AF_LOCAL: + return 1; + default: + break; + } + + return 0; +} + + +/* logit - report events of interest via the syslog daemon */ +void +logit(int severity, struct sockaddr *addr, rpcproc_t procnum, rpcprog_t prognum, + const char *text) +{ + const char *procname; + char procbuf[32]; + char *progname; + char progbuf[32]; + char fromname[NI_MAXHOST]; + struct rpcent *rpc; + static const char *procmap[] = { + /* RPCBPROC_NULL */ "null", + /* RPCBPROC_SET */ "set", + /* RPCBPROC_UNSET */ "unset", + /* RPCBPROC_GETADDR */ "getport/addr", + /* RPCBPROC_DUMP */ "dump", + /* RPCBPROC_CALLIT */ "callit", + /* RPCBPROC_GETTIME */ "gettime", + /* RPCBPROC_UADDR2TADDR */ "uaddr2taddr", + /* RPCBPROC_TADDR2UADDR */ "taddr2uaddr", + /* RPCBPROC_GETVERSADDR */ "getversaddr", + /* RPCBPROC_INDIRECT */ "indirect", + /* RPCBPROC_GETADDRLIST */ "getaddrlist", + /* RPCBPROC_GETSTAT */ "getstat" + }; + + /* + * Fork off a process or the portmap daemon might hang while + * getrpcbynumber() or syslog() does its thing. + */ + + if (fork() == 0) { + setproctitle("logit"); + + /* Try to map program number to name. */ + + if (prognum == 0) { + progname = __UNCONST(""); + } else if ((rpc = getrpcbynumber((int) prognum))) { + progname = rpc->r_name; + } else { + snprintf(progname = progbuf, sizeof(progbuf), "%u", + (unsigned)prognum); + } + + /* Try to map procedure number to name. */ + + if (procnum >= (sizeof procmap / sizeof (char *))) { + snprintf(procbuf, sizeof procbuf, "%u", + (unsigned)procnum); + procname = procbuf; + } else + procname = procmap[procnum]; + + /* Write syslog record. */ + + if (addr->sa_family == AF_LOCAL) + strlcpy(fromname, "local", sizeof(fromname)); + else + getnameinfo(addr, addr->sa_len, fromname, + sizeof fromname, NULL, 0, NI_NUMERICHOST); + + syslog(severity, "connect from %s to %s(%s)%s", + fromname, procname, progname, text); + _exit(0); + } +} + +int +check_callit(SVCXPRT *xprt, struct r_rmtcall_args *args, int versnum) +{ + struct sockaddr *sa = (struct sockaddr *)svc_getrpccaller(xprt)->buf; + + /* + * Always allow calling NULLPROC + */ + if (args->rmt_proc == 0) + return 1; + + /* + * XXX - this special casing sucks. + */ + switch (args->rmt_prog) { + case RPCBPROG: + /* + * Allow indirect calls to ourselves in insecure mode. + * The is_loopback checks aren't useful then anyway. + */ + if (!insecure) + goto deny; + break; + case MOUNTPROG: + if (args->rmt_proc != MOUNTPROC_MNT && + args->rmt_proc != MOUNTPROC_UMNT) + break; + goto deny; + case YPBINDPROG: + if (args->rmt_proc != YPBINDPROC_SETDOM) + break; + /* FALLTHROUGH */ + case YPPASSWDPROG: + case NFS_PROGRAM: + case RQUOTAPROG: + goto deny; + case YPPROG: + switch (args->rmt_proc) { + case YPPROC_ALL: + case YPPROC_MATCH: + case YPPROC_FIRST: + case YPPROC_NEXT: + goto deny; + default: + break; + } + default: + break; + } + + return 1; +deny: + logit(deny_severity, sa, args->rmt_proc, args->rmt_prog, + ": indirect call not allowed"); + + return 0; +} |