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. Also, require
21 * that requests to set/unset the NFSD port come form a privileged port.
23 * If compiled with -DHOSTS_ACCESS, reject requests from hosts that are not
24 * authorized by the /etc/hosts.{allow,deny} files. The local system is
25 * always treated as an authorized host. The access control tables are never
26 * consulted for requests from the local system, and are always consulted
27 * for requests from other hosts. Access control is based on IP addresses
28 * only; attempts to map an address to a host name might cause the
31 * Author: Wietse Venema (wietse@wzv.win.tue.nl), dept. of Mathematics and
32 * Computing Science, Eindhoven University of Technology, The Netherlands.
36 #include <sys/types.h>
39 #include <rpc/pmap_prot.h>
42 #include <sys/signal.h>
44 #include <netinet/in.h>
45 #include <rpc/rpcent.h>
50 #include <arpa/inet.h>
53 #include "pmap_check.h"
55 /* Explicit #defines in case the include files are not available. */
57 #define NFSPROG ((u_long) 100003)
58 #define MOUNTPROG ((u_long) 100005)
59 #define YPXPROG ((u_long) 100069)
60 #define YPPROG ((u_long) 100004)
61 #define YPPROC_DOMAIN_NONACK ((u_long) 2)
62 #define MOUNTPROC_MNT ((u_long) 1)
65 static void logit(int severity, struct sockaddr_in *addr,
66 u_long procnum, u_long prognum, const char *text);
67 static void toggle_verboselog(int sig);
68 int verboselog __attribute ((visibility ("hidden"))) = 0;
69 int allow_severity __attribute ((visibility ("hidden"))) = LOG_INFO;
70 int deny_severity __attribute ((visibility ("hidden"))) = LOG_WARNING;
72 /* A handful of macros for "readability". */
74 #define reserved_port(p) ((p) < IPPORT_RESERVED)
76 #define unreserved_port(p) (IPPORT_RESERVED <= (p) && (p) != NFS_PORT)
78 #define legal_port(a,p) \
79 (reserved_port(ntohs((a)->sin_port)) || unreserved_port(p))
81 #define log_bad_port(addr, proc, prog) \
82 logit(deny_severity, addr, proc, prog, ": request from unprivileged port")
84 #define log_bad_host(addr, proc, prog) \
85 logit(deny_severity, addr, proc, prog, ": request from unauthorized host")
87 #define log_bad_owner(addr, proc, prog) \
88 logit(deny_severity, addr, proc, prog, ": request from non-local host")
90 #define log_no_forward(addr, proc, prog) \
91 logit(deny_severity, addr, proc, prog, ": request not forwarded")
93 #define log_client(addr, proc, prog) \
94 logit(allow_severity, addr, proc, prog, "")
96 /* check_startup - additional startup code */
98 void check_startup(void)
102 * Give up root privileges so that we can never allocate a privileged
103 * port when forwarding an rpc request.
107 if (setuid(daemon_uid) == -1) {
108 syslog(LOG_ERR, "setuid(1) failed: %m");
111 (void) signal(SIGINT, toggle_verboselog);
117 good_client(struct sockaddr_in *addr)
119 if (hosts_ctl((char*)("portmap"), (char*)(""), inet_ntoa(addr->sin_addr), (char*)("")))
127 /* Check the hostname. */
128 hp = gethostbyaddr ((const char *) &(addr->sin_addr),
129 sizeof (addr->sin_addr), AF_INET);
134 /* must make sure the hostent is authoritative. */
135 tmpname = alloca (strlen (hp->h_name) + 1);
136 strcpy (tmpname, hp->h_name);
137 hp = gethostbyname(tmpname);
139 /* now make sure the "addr->sin_addr" is on the list */
140 for (sp = hp->h_addr_list ; *sp ; sp++) {
141 if (memcmp(*sp, &(addr->sin_addr), hp->h_length)==0)
148 /* never heard of it. misconfigured DNS? */
151 /* Check the official name first. */
152 if (hosts_ctl((char*)("portmap"), (char*)(""), hp->h_name, (char*)("")))
156 for (sp = hp->h_aliases; *sp ; sp++) {
157 if (hosts_ctl((char*)("portmap"), (char*)(""), *sp, (char*)("")))
161 #endif /* ENABLE_DNS */
164 #endif /* HOSTS_ACCESS */
166 /* check_default - additional checks for NULL, DUMP, GETPORT and unknown */
169 check_default(struct sockaddr_in *addr, u_long proc,
173 if (!(from_local(addr) || good_client(addr))) {
174 log_bad_host(addr, proc, prog);
179 log_client(addr, proc, prog);
183 /* check_privileged_port - additional checks for privileged-port updates */
186 check_privileged_port(struct sockaddr_in *addr, u_long proc,
187 u_long prog, u_long port)
190 if (!legal_port(addr, port)) {
191 log_bad_port(addr, proc, prog);
198 /* check_setunset - additional checks for update requests */
200 #ifdef LOOPBACK_SETUNSET
203 check_setunset(SVCXPRT *xprt, SVCXPRT *ludp_xprt, SVCXPRT *ltcp_xprt,
204 u_long proc, u_long prog, u_long port)
206 struct sockaddr_in *addr = svc_getcaller(xprt);
208 if (xprt != ludp_xprt && xprt != ltcp_xprt) {
210 (void) good_client(addr); /* because of side effects */
212 log_bad_owner(addr, proc, prog);
215 if (port && !check_privileged_port(addr, proc, prog, port))
218 log_client(addr, proc, prog);
225 check_setunset(struct sockaddr_in *addr, u_long proc,
226 u_long prog, u_long port)
228 if (!from_local(addr)) {
230 (void) good_client(addr); /* because of side effects */
232 log_bad_owner(addr, proc, prog);
235 if (port && !check_privileged_port(addr, proc, prog, port))
238 log_client(addr, proc, prog);
244 /* check_callit - additional checks for forwarded requests */
247 check_callit(struct sockaddr_in *addr, u_long proc,
248 u_long prog, u_long aproc)
251 if (!(from_local(addr) || good_client(addr))) {
252 log_bad_host(addr, proc, prog);
256 if (prog == PMAPPROG || prog == NFSPROG || prog == YPXPROG ||
257 (prog == MOUNTPROG && aproc == MOUNTPROC_MNT) ||
258 (prog == YPPROG && aproc != YPPROC_DOMAIN_NONACK)) {
259 log_no_forward(addr, proc, prog);
263 log_client(addr, proc, prog);
267 /* toggle_verboselog - toggle verbose logging flag */
269 static void toggle_verboselog(int sig)
271 (void) signal(sig, toggle_verboselog);
272 verboselog = !verboselog;
275 /* logit - report events of interest via the syslog daemon */
277 static void logit(int severity, struct sockaddr_in *addr,
278 u_long procnum, u_long prognum, const char *text)
280 const char *procname;
281 char procbuf[4 * sizeof(u_long)];
282 const char *progname;
283 char progbuf[4 * sizeof(u_long)];
289 struct proc_map *procp;
290 static struct proc_map procmap[] = {
291 { PMAPPROC_CALLIT, "callit" },
292 { PMAPPROC_DUMP, "dump"} ,
293 { PMAPPROC_GETPORT, "getport"} ,
294 { PMAPPROC_NULL, "null"} ,
295 { PMAPPROC_SET, "set"} ,
296 { PMAPPROC_UNSET, "unset"} ,
301 * Fork off a process or the portmap daemon might hang while
302 * getrpcbynumber() or syslog() does its thing.
309 /* Try to map program number to name. */
313 } else if ((rpc = getrpcbynumber((int) prognum))) {
314 progname = rpc->r_name;
316 sprintf(progbuf, "%lu", prognum);
320 /* Try to map procedure number to name. */
322 for (procp = procmap; procp->proc && procp->code != procnum; procp++)
324 if ((procname = procp->proc) == 0)
326 sprintf(procbuf, "%lu", (u_long) procnum);
330 /* Write syslog record. */
332 syslog(severity, "connect from %s to %s(%s)%s",
333 inet_ntoa(addr->sin_addr), procname, progname, text);