diff options
Diffstat (limited to 'usr.sbin/portmap/pmap_check.c')
-rw-r--r-- | usr.sbin/portmap/pmap_check.c | 251 |
1 files changed, 251 insertions, 0 deletions
diff --git a/usr.sbin/portmap/pmap_check.c b/usr.sbin/portmap/pmap_check.c new file mode 100644 index 0000000..1d1ed61 --- /dev/null +++ b/usr.sbin/portmap/pmap_check.c @@ -0,0 +1,251 @@ + /* + * pmap_check - additional portmap security. + * + * Always reject non-local requests to update the portmapper tables. + * + * Refuse to forward mount requests to the nfs mount daemon. Otherwise, the + * requests would appear to come from the local system, and nfs export + * restrictions could be bypassed. + * + * Refuse to forward requests to the nfsd process. + * + * Refuse to forward requests to NIS (YP) daemons; The only exception is the + * YPPROC_DOMAIN_NONACK broadcast rpc call that is used to establish initial + * contact with the NIS server. + * + * Always allocate an unprivileged port when forwarding a request. + * + * If compiled with -DCHECK_PORT, require that requests to register or + * unregister a privileged port come from a privileged port. This makes it + * more difficult to replace a critical service by a trojan. + * + * If compiled with -DHOSTS_ACCESS, reject requests from hosts that are not + * authorized by the /etc/hosts.{allow,deny} files. The local system is + * always treated as an authorized host. The access control tables are never + * consulted for requests from the local system, and are always consulted + * for requests from other hosts. Access control is based on IP addresses + * only; attempts to map an address to a host name might cause the + * portmapper to hang. + * + * Author: Wietse Venema (wietse@wzv.win.tue.nl), dept. of Mathematics and + * Computing Science, Eindhoven University of Technology, The Netherlands. + */ + +#ifndef lint +static char sccsid[] = "@(#) pmap_check.c 1.6 93/11/21 20:58:59"; +#endif + +#include <rpc/rpc.h> +#include <rpc/pmap_prot.h> +#include <syslog.h> +#include <netdb.h> +#include <sys/signal.h> + +extern char *inet_ntoa(); + +#include "pmap_check.h" + +/* Explicit #defines in case the include files are not available. */ + +#define NFSPROG ((u_long) 100003) +#define MOUNTPROG ((u_long) 100005) +#define YPXPROG ((u_long) 100069) +#define YPPROG ((u_long) 100004) +#define YPPROC_DOMAIN_NONACK ((u_long) 2) +#define MOUNTPROC_MNT ((u_long) 1) + +static void logit(); +static void toggle_verboselog(); +int verboselog = 0; +int allow_severity = LOG_INFO; +int deny_severity = LOG_WARNING; + +/* A handful of macros for "readability". */ + +#define good_client(a) hosts_ctl("portmap", "", inet_ntoa(a->sin_addr), "") + +#define legal_port(a,p) \ + (ntohs((a)->sin_port) < IPPORT_RESERVED || (p) >= IPPORT_RESERVED) + +#define log_bad_port(addr, proc, prog) \ + logit(deny_severity, addr, proc, prog, ": request from unprivileged port") + +#define log_bad_host(addr, proc, prog) \ + logit(deny_severity, addr, proc, prog, ": request from unauthorized host") + +#define log_bad_owner(addr, proc, prog) \ + logit(deny_severity, addr, proc, prog, ": request from non-local host") + +#define log_no_forward(addr, proc, prog) \ + logit(deny_severity, addr, proc, prog, ": request not forwarded") + +#define log_client(addr, proc, prog) \ + logit(allow_severity, addr, proc, prog, "") + +/* check_startup - additional startup code */ + +void check_startup() +{ + + /* + * Give up root privileges so that we can never allocate a privileged + * port when forwarding an rpc request. + */ + if (setuid(1) == -1) { + syslog(LOG_ERR, "setuid(1) failed: %m"); + exit(1); + } + (void) signal(SIGINT, toggle_verboselog); +} + +/* check_default - additional checks for NULL, DUMP, GETPORT and unknown */ + +check_default(addr, proc, prog) +struct sockaddr_in *addr; +u_long proc; +u_long prog; +{ +#ifdef HOSTS_ACCESS + if (!(from_local(addr) || good_client(addr))) { + log_bad_host(addr, proc, prog); + return (FALSE); + } +#endif + if (verboselog) + log_client(addr, proc, prog); + return (TRUE); +} + +/* check_privileged_port - additional checks for privileged-port updates */ + +check_privileged_port(addr, proc, prog, port) +struct sockaddr_in *addr; +u_long proc; +u_long prog; +u_long port; +{ +#ifdef CHECK_PORT + if (!legal_port(addr, port)) { + log_bad_port(addr, proc, prog); + return (FALSE); + } +#endif + return (TRUE); +} + +/* check_setunset - additional checks for update requests */ + +check_setunset(addr, proc, prog, port) +struct sockaddr_in *addr; +u_long proc; +u_long prog; +u_long port; +{ + if (!from_local(addr)) { +#ifdef HOSTS_ACCESS + (void) good_client(addr); /* because of side effects */ +#endif + log_bad_owner(addr, proc, prog); + return (FALSE); + } + if (port && !check_privileged_port(addr, proc, prog, port)) + return (FALSE); + if (verboselog) + log_client(addr, proc, prog); + return (TRUE); +} + +/* check_callit - additional checks for forwarded requests */ + +check_callit(addr, proc, prog, aproc) +struct sockaddr_in *addr; +u_long proc; +u_long prog; +u_long aproc; +{ +#ifdef HOSTS_ACCESS + if (!(from_local(addr) || good_client(addr))) { + log_bad_host(addr, proc, prog); + return (FALSE); + } +#endif + if (prog == PMAPPROG || prog == NFSPROG || prog == YPXPROG || + (prog == MOUNTPROG && aproc == MOUNTPROC_MNT) || + (prog == YPPROG && aproc != YPPROC_DOMAIN_NONACK)) { + log_no_forward(addr, proc, prog); + return (FALSE); + } + if (verboselog) + log_client(addr, proc, prog); + return (TRUE); +} + +/* toggle_verboselog - toggle verbose logging flag */ + +static void toggle_verboselog(sig) +int sig; +{ + (void) signal(sig, toggle_verboselog); + verboselog = !verboselog; +} + +/* logit - report events of interest via the syslog daemon */ + +static void logit(severity, addr, procnum, prognum, text) +int severity; +struct sockaddr_in *addr; +u_long procnum; +u_long prognum; +char *text; +{ + char *procname; + char procbuf[4 * sizeof(u_long)]; + char *progname; + char progbuf[4 * sizeof(u_long)]; + struct rpcent *rpc; + struct proc_map { + u_long code; + char *proc; + }; + struct proc_map *procp; + static struct proc_map procmap[] = { + PMAPPROC_CALLIT, "callit", + PMAPPROC_DUMP, "dump", + PMAPPROC_GETPORT, "getport", + PMAPPROC_NULL, "null", + PMAPPROC_SET, "set", + PMAPPROC_UNSET, "unset", + 0, 0, + }; + + /* + * Fork off a process or the portmap daemon might hang while + * getrpcbynumber() or syslog() does its thing. + */ + + if (fork() == 0) { + + /* Try to map program number to name. */ + + if (prognum == 0) { + progname = ""; + } else if (rpc = getrpcbynumber((int) prognum)) { + progname = rpc->r_name; + } else { + sprintf(progname = progbuf, "%lu", prognum); + } + + /* Try to map procedure number to name. */ + + for (procp = procmap; procp->proc && procp->code != procnum; procp++) + /* void */ ; + if ((procname = procp->proc) == 0) + sprintf(procname = procbuf, "%lu", (u_long) procnum); + + /* Write syslog record. */ + + syslog(severity, "connect from %s to %s(%s)%s", + inet_ntoa(addr->sin_addr), procname, progname, text); + exit(0); + } +} |