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>
48 #include <arpa/inet.h>
51 #include "pmap_check.h"
53 /* Explicit #defines in case the include files are not available. */
55 #define NFSPROG ((u_long) 100003)
56 #define MOUNTPROG ((u_long) 100005)
57 #define YPXPROG ((u_long) 100069)
58 #define YPPROG ((u_long) 100004)
59 #define YPPROC_DOMAIN_NONACK ((u_long) 2)
60 #define MOUNTPROC_MNT ((u_long) 1)
63 static void logit(int severity
, struct sockaddr_in
*addr
,
64 u_long procnum
, u_long prognum
, char *text
);
65 static void toggle_verboselog(int sig
);
66 int verboselog
__attribute ((visibility ("hidden"))) = 0;
67 int allow_severity
__attribute ((visibility ("hidden"))) = LOG_INFO
;
68 int deny_severity
__attribute ((visibility ("hidden"))) = LOG_WARNING
;
70 /* A handful of macros for "readability". */
72 #define reserved_port(p) (IPPORT_RESERVED/2 < (p) && (p) < IPPORT_RESERVED)
74 #define unreserved_port(p) (IPPORT_RESERVED <= (p) && (p) != NFS_PORT)
76 #define legal_port(a,p) \
77 (reserved_port(ntohs((a)->sin_port)) || unreserved_port(p))
79 #define log_bad_port(addr, proc, prog) \
80 logit(deny_severity, addr, proc, prog, ": request from unprivileged port")
82 #define log_bad_host(addr, proc, prog) \
83 logit(deny_severity, addr, proc, prog, ": request from unauthorized host")
85 #define log_bad_owner(addr, proc, prog) \
86 logit(deny_severity, addr, proc, prog, ": request from non-local host")
88 #define log_no_forward(addr, proc, prog) \
89 logit(deny_severity, addr, proc, prog, ": request not forwarded")
91 #define log_client(addr, proc, prog) \
92 logit(allow_severity, addr, proc, prog, "")
94 /* check_startup - additional startup code */
96 void check_startup(void)
100 * Give up root privileges so that we can never allocate a privileged
101 * port when forwarding an rpc request.
105 if (setuid(daemon_uid
) == -1) {
106 syslog(LOG_ERR
, "setuid(1) failed: %m");
109 (void) signal(SIGINT
, toggle_verboselog
);
115 good_client(struct sockaddr_in
*addr
)
117 if (hosts_ctl("portmap", "", inet_ntoa(addr
->sin_addr
), ""))
125 /* Check the hostname. */
126 hp
= gethostbyaddr ((const char *) &(addr
->sin_addr
),
127 sizeof (addr
->sin_addr
), AF_INET
);
132 /* must make sure the hostent is authoritative. */
133 tmpname
= alloca (strlen (hp
->h_name
) + 1);
134 strcpy (tmpname
, hp
->h_name
);
135 hp
= gethostbyname(tmpname
);
137 /* now make sure the "addr->sin_addr" is on the list */
138 for (sp
= hp
->h_addr_list
; *sp
; sp
++) {
139 if (memcmp(*sp
, &(addr
->sin_addr
), hp
->h_length
)==0)
146 /* never heard of it. misconfigured DNS? */
149 /* Check the official name first. */
150 if (hosts_ctl("portmap", "", hp
->h_name
, ""))
154 for (sp
= hp
->h_aliases
; *sp
; sp
++) {
155 if (hosts_ctl("portmap", "", *sp
, ""))
159 #endif /* ENABLE_DNS */
162 #endif /* HOSTS_ACCESS */
164 /* check_default - additional checks for NULL, DUMP, GETPORT and unknown */
167 check_default(struct sockaddr_in
*addr
, u_long proc
,
171 if (!(from_local(addr
) || good_client(addr
))) {
172 log_bad_host(addr
, proc
, prog
);
177 log_client(addr
, proc
, prog
);
181 /* check_privileged_port - additional checks for privileged-port updates */
184 check_privileged_port(struct sockaddr_in
*addr
, u_long proc
,
185 u_long prog
, u_long port
)
188 if (!legal_port(addr
, port
)) {
189 log_bad_port(addr
, proc
, prog
);
196 /* check_setunset - additional checks for update requests */
198 #ifdef LOOPBACK_SETUNSET
201 check_setunset(SVCXPRT
*xprt
, SVCXPRT
*ludp_xprt
, SVCXPRT
*ltcp_xprt
,
202 u_long proc
, u_long prog
, u_long port
)
204 struct sockaddr_in
*addr
= svc_getcaller(xprt
);
206 if (xprt
!= ludp_xprt
&& xprt
!= ltcp_xprt
) {
208 (void) good_client(addr
); /* because of side effects */
210 log_bad_owner(addr
, proc
, prog
);
213 if (port
&& !check_privileged_port(addr
, proc
, prog
, port
))
216 log_client(addr
, proc
, prog
);
223 check_setunset(struct sockaddr_in
*addr
, u_long proc
,
224 u_long prog
, u_long port
)
226 if (!from_local(addr
)) {
228 (void) good_client(addr
); /* because of side effects */
230 log_bad_owner(addr
, proc
, prog
);
233 if (port
&& !check_privileged_port(addr
, proc
, prog
, port
))
236 log_client(addr
, proc
, prog
);
242 /* check_callit - additional checks for forwarded requests */
245 check_callit(struct sockaddr_in
*addr
, u_long proc
,
246 u_long prog
, u_long aproc
)
249 if (!(from_local(addr
) || good_client(addr
))) {
250 log_bad_host(addr
, proc
, prog
);
254 if (prog
== PMAPPROG
|| prog
== NFSPROG
|| prog
== YPXPROG
||
255 (prog
== MOUNTPROG
&& aproc
== MOUNTPROC_MNT
) ||
256 (prog
== YPPROG
&& aproc
!= YPPROC_DOMAIN_NONACK
)) {
257 log_no_forward(addr
, proc
, prog
);
261 log_client(addr
, proc
, prog
);
265 /* toggle_verboselog - toggle verbose logging flag */
267 static void toggle_verboselog(int sig
)
269 (void) signal(sig
, toggle_verboselog
);
270 verboselog
= !verboselog
;
273 /* logit - report events of interest via the syslog daemon */
275 static void logit(int severity
, struct sockaddr_in
*addr
,
276 u_long procnum
, u_long prognum
, char *text
)
279 char procbuf
[4 * sizeof(u_long
)];
281 char progbuf
[4 * sizeof(u_long
)];
287 struct proc_map
*procp
;
288 static struct proc_map procmap
[] = {
289 { PMAPPROC_CALLIT
, "callit" },
290 { PMAPPROC_DUMP
, "dump"} ,
291 { PMAPPROC_GETPORT
, "getport"} ,
292 { PMAPPROC_NULL
, "null"} ,
293 { PMAPPROC_SET
, "set"} ,
294 { PMAPPROC_UNSET
, "unset"} ,
299 * Fork off a process or the portmap daemon might hang while
300 * getrpcbynumber() or syslog() does its thing.
305 /* Try to map program number to name. */
309 } else if ((rpc
= getrpcbynumber((int) prognum
))) {
310 progname
= rpc
->r_name
;
312 sprintf(progname
= progbuf
, "%lu", prognum
);
315 /* Try to map procedure number to name. */
317 for (procp
= procmap
; procp
->proc
&& procp
->code
!= procnum
; procp
++)
319 if ((procname
= procp
->proc
) == 0)
320 sprintf(procname
= procbuf
, "%lu", (u_long
) procnum
);
322 /* Write syslog record. */
324 syslog(severity
, "connect from %s to %s(%s)%s",
325 inet_ntoa(addr
->sin_addr
), procname
, progname
, text
);