2 * pmap_check - additional portmap security.
4 * Always reject non-local requests to update the portmapper tables.
6 * Refuse to forward mount requests to the nfs mount daemon. Otherwise, the
7 * requests would appear to come from the local system, and nfs export
8 * restrictions could be bypassed.
10 * Refuse to forward requests to the nfsd process.
12 * Refuse to forward requests to NIS (YP) daemons; The only exception is the
13 * YPPROC_DOMAIN_NONACK broadcast rpc call that is used to establish initial
14 * contact with the NIS server.
16 * Always allocate an unprivileged port when forwarding a request.
18 * If compiled with -DCHECK_PORT, require that requests to register or
19 * unregister a privileged port come from a privileged port. This makes it
20 * more difficult to replace a critical service by a trojan.
22 * If compiled with -DHOSTS_ACCESS, reject requests from hosts that are not
23 * authorized by the /etc/hosts.{allow,deny} files. The local system is
24 * always treated as an authorized host. The access control tables are never
25 * consulted for requests from the local system, and are always consulted
26 * for requests from other hosts. Access control is based on IP addresses
27 * only; attempts to map an address to a host name might cause the
30 * Author: Wietse Venema (wietse@wzv.win.tue.nl), dept. of Mathematics and
31 * Computing Science, Eindhoven University of Technology, The Netherlands.
35 * @(#) pmap_check.c 1.6 93/11/21 20:58:59
36 * $FreeBSD: src/usr.sbin/portmap/pmap_check.c,v 1.6 2000/01/15 23:08:28 brian Exp $
37 * $DragonFly: src/usr.sbin/portmap/pmap_check.c,v 1.3 2003/11/03 19:31:40 eirikn Exp $
41 #include <sys/types.h>
42 #include <sys/socket.h>
43 #include <netinet/in.h>
44 #include <arpa/inet.h>
47 #include <rpc/pmap_prot.h>
50 #include <sys/signal.h>
52 #include "pmap_check.h"
54 /* Explicit #defines in case the include files are not available. */
56 #define NFSPROG ((u_long) 100003)
57 #define MOUNTPROG ((u_long) 100005)
58 #define YPXPROG ((u_long) 100069)
59 #define YPPROG ((u_long) 100004)
60 #define YPPROC_DOMAIN_NONACK ((u_long) 2)
61 #define MOUNTPROC_MNT ((u_long) 1)
63 static void logit(int, struct sockaddr_in *, u_long, u_long, const char *);
64 static void toggle_verboselog(int);
67 int allow_severity = LOG_INFO;
68 int deny_severity = LOG_WARNING;
70 /* A handful of macros for "readability". */
72 #define good_client(a) hosts_ctl("portmap", "", inet_ntoa(a->sin_addr), "")
74 #define legal_port(a,p) \
75 (ntohs((a)->sin_port) < IPPORT_RESERVED || (p) >= IPPORT_RESERVED)
77 #define log_bad_port(addr, proc, prog) \
78 logit(deny_severity, addr, proc, prog, ": request from unprivileged port")
80 #define log_bad_host(addr, proc, prog) \
81 logit(deny_severity, addr, proc, prog, ": request from unauthorized host")
83 #define log_bad_owner(addr, proc, prog) \
84 logit(deny_severity, addr, proc, prog, ": request from non-local host")
86 #define log_no_forward(addr, proc, prog) \
87 logit(deny_severity, addr, proc, prog, ": request not forwarded")
89 #define log_client(addr, proc, prog) \
90 logit(allow_severity, addr, proc, prog, "")
92 /* check_startup - additional startup code */
99 * Give up root privileges so that we can never allocate a privileged
100 * port when forwarding an rpc request.
102 if (setuid(1) == -1) {
103 syslog(LOG_ERR, "setuid(1) failed: %m");
106 (void) signal(SIGINT, toggle_verboselog);
109 /* check_default - additional checks for NULL, DUMP, GETPORT and unknown */
112 check_default(addr, proc, prog)
113 struct sockaddr_in *addr;
117 if (!(from_local(addr) || good_client(addr))) {
118 log_bad_host(addr, proc, prog);
123 log_client(addr, proc, prog);
127 /* check_privileged_port - additional checks for privileged-port updates */
130 check_privileged_port(addr, proc, prog, port)
131 struct sockaddr_in *addr;
132 u_long proc, prog, port;
135 if (!legal_port(addr, port)) {
136 log_bad_port(addr, proc, prog);
143 /* check_setunset - additional checks for update requests */
146 check_setunset(addr, proc, prog, port)
147 struct sockaddr_in *addr;
148 u_long proc, prog, port;
150 if (!from_local(addr)) {
152 (void) good_client(addr); /* because of side effects */
154 log_bad_owner(addr, proc, prog);
157 if (port && !check_privileged_port(addr, proc, prog, port))
160 log_client(addr, proc, prog);
164 /* check_callit - additional checks for forwarded requests */
167 check_callit(addr, proc, prog, aproc)
168 struct sockaddr_in *addr;
169 u_long proc, prog, aproc;
172 if (!(from_local(addr) || good_client(addr))) {
173 log_bad_host(addr, proc, prog);
177 if (prog == PMAPPROG || prog == NFSPROG || prog == YPXPROG ||
178 (prog == MOUNTPROG && aproc == MOUNTPROC_MNT) ||
179 (prog == YPPROG && aproc != YPPROC_DOMAIN_NONACK)) {
180 log_no_forward(addr, proc, prog);
184 log_client(addr, proc, prog);
188 /* toggle_verboselog - toggle verbose logging flag */
191 toggle_verboselog(sig)
194 (void) signal(sig, toggle_verboselog);
195 verboselog = !verboselog;
198 /* logit - report events of interest via the syslog daemon */
201 logit(severity, addr, procnum, prognum, text)
203 struct sockaddr_in *addr;
204 u_long procnum, prognum;
207 const char *procname;
208 char procbuf[4 * sizeof(u_long)];
209 const char *progname;
210 char progbuf[4 * sizeof(u_long)];
216 struct proc_map *procp;
217 static struct proc_map procmap[] = {
218 {PMAPPROC_CALLIT, "callit"},
219 {PMAPPROC_DUMP, "dump"},
220 {PMAPPROC_GETPORT, "getport"},
221 {PMAPPROC_NULL, "null"},
222 {PMAPPROC_SET, "set"},
223 {PMAPPROC_UNSET, "unset"},
228 * Fork off a process or the portmap daemon might hang while
229 * getrpcbynumber() or syslog() does its thing.
234 /* Try to map program number to name. */
238 } else if ((rpc = getrpcbynumber((int) prognum))) {
239 progname = rpc->r_name;
241 sprintf(progbuf, "%lu", prognum);
245 /* Try to map procedure number to name. */
247 for (procp = procmap; procp->proc && procp->code != procnum; procp++)
249 if ((procname = procp->proc) == 0) {
250 sprintf(procbuf, "%lu", (u_long) procnum);
254 /* Write syslog record. */
256 syslog(severity, "connect from %s to %s(%s)%s",
257 inet_ntoa(addr->sin_addr), procname, progname, text);